From 04df7f147c6e08b28113173328d7e03fce381af9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 16 Apr 2018 00:08:52 -0700 Subject: [PATCH 001/214] update macros.nim: followup on pull #7598 (#7619) @Araq @krux02 https://github.com/nim-lang/Nim/pull/7598 seemed inaccurate eg for NLineInfo there's `mNLineInfo` but no opcNLineInfo --- lib/core/macros.nim | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 7217475c61..993756b282 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -14,11 +14,8 @@ include "system/inclrtl" ## .. include:: ../../doc/astspec.txt -# If you look for the implementation of the magic symbols, copy the -# magic string and open the file "../../compiler/vm.nim" and search -# for the magic string with the prefix "opc". For example the -# implementation of ``{.magic: "FooBar".}`` will be right under -# ``of opcFooBar:``. +# If you look for the implementation of the magic symbol +# ``{.magic: "Foo".}``, search for `mFoo` and `opcFoo`. type NimNodeKind* = enum From bf6e82a8611428fde85a0017166f316599c4228e Mon Sep 17 00:00:00 2001 From: skilchen Date: Mon, 16 Apr 2018 17:40:54 +0200 Subject: [PATCH 002/214] there is no hour 0 in am/pm time --- lib/pure/times.nim | 22 +++++++++++++++------- tests/stdlib/ttimes.nim | 6 ++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index dc216477b0..e45135612e 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1158,12 +1158,16 @@ proc formatToken(dt: DateTime, token: string, buf: var string) = of "dddd": buf.add($dt.weekday) of "h": - buf.add($(if dt.hour > 12: dt.hour - 12 else: dt.hour)) + if dt.hour == 0: buf.add("12") + else: buf.add($(if dt.hour > 12: dt.hour - 12 else: dt.hour)) of "hh": - let amerHour = if dt.hour > 12: dt.hour - 12 else: dt.hour - if amerHour < 10: - buf.add('0') - buf.add($amerHour) + if dt.hour == 0: + buf.add("12") + else: + let amerHour = if dt.hour > 12: dt.hour - 12 else: dt.hour + if amerHour < 10: + buf.add('0') + buf.add($amerHour) of "H": buf.add($dt.hour) of "HH": @@ -1488,11 +1492,15 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) = dt.second = value[j..j+1].parseInt() j += 2 of "t": - if value[j] == 'P' and dt.hour > 0 and dt.hour < 12: + if value[j] == 'A' and dt.hour == 12: + dt.hour = 0 + elif value[j] == 'P' and dt.hour > 0 and dt.hour < 12: dt.hour += 12 j += 1 of "tt": - if value[j..j+1] == "PM" and dt.hour > 0 and dt.hour < 12: + if value[j..j+1] == "AM" and dt.hour == 12: + dt.hour = 0 + elif value[j..j+1] == "PM" and dt.hour > 0 and dt.hour < 12: dt.hour += 12 j += 2 of "yy": diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index f359652865..4f1a43f151 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -28,6 +28,12 @@ t.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" & t.checkFormat("yyyyMMddhhmmss", "20380119031407") +# issue 7620 +let t7620_am = parse("4/15/2017 12:01:02 AM +0", "M/d/yyyy' 'h:mm:ss' 'tt' 'z", utc()) +t7620_am.checkFormat("M/d/yyyy' 'h:mm:ss' 'tt' 'z", "4/15/2017 12:01:02 AM +0") +let t7620_pm = parse("4/15/2017 12:01:02 PM +0", "M/d/yyyy' 'h:mm:ss' 'tt' 'z", utc()) +t7620_pm.checkFormat("M/d/yyyy' 'h:mm:ss' 'tt' 'z", "4/15/2017 12:01:02 PM +0") + let t2 = fromUnix(160070789).utc # Mon 27 Jan 16:06:29 GMT 1975 t2.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" & " ss t tt y yy yyy yyyy yyyyy z zz zzz", From 412cd61dabe160708c502e37a48b9c3c7c2c6017 Mon Sep 17 00:00:00 2001 From: Dmitry Atamanov Date: Mon, 16 Apr 2018 20:37:08 +0300 Subject: [PATCH 003/214] Fixes #7595 (#7623) * Fixes #7595 * Add brackets * Fix for treeRepr and lispRepr too --- lib/core/macros.nim | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 993756b282..b050eb6c88 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -706,8 +706,7 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} = res.add(($n.kind).substr(3)) case n.kind - of nnkEmpty: discard # same as nil node in this representation - of nnkNilLit: res.add(" nil") + of nnkEmpty, nnkNilLit: discard # same as nil node in this representation of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal) of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal) of nnkStrLit..nnkTripleStrLit, nnkIdent, nnkSym: @@ -730,8 +729,7 @@ proc lispRepr*(n: NimNode): string {.compileTime, benign.} = add(result, "(") case n.kind - of nnkEmpty: discard # same as nil node in this representation - of nnkNilLit: add(result, "nil") + of nnkEmpty, nnkNilLit: discard # same as nil node in this representation of nnkCharLit..nnkInt64Lit: add(result, $n.intVal) of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal) of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkident, nnkSym: @@ -766,7 +764,7 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} = ## See also `repr`, `treeRepr`, and `lispRepr`. const - NodeKinds = {nnkEmpty, nnkNilLit, nnkIdent, nnkSym, nnkNone, nnkCommentStmt} + NodeKinds = {nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkCommentStmt} LitKinds = {nnkCharLit..nnkInt64Lit, nnkFloatLit..nnkFloat64Lit, nnkStrLit..nnkTripleStrLit} proc traverse(res: var string, level: int, n: NimNode) {.benign.} = @@ -775,12 +773,13 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} = res.add("new" & ($n.kind).substr(3) & "Node(") elif n.kind in LitKinds: res.add("newLit(") + elif n.kind == nnkNilLit: + res.add("newNilLit()") else: res.add($n.kind) case n.kind - of nnkEmpty: discard - of nnkNilLit: res.add("nil") + of nnkEmpty, nnkNilLit: discard of nnkCharLit: res.add("'" & $chr(n.intVal) & "'") of nnkIntLit..nnkInt64Lit: res.add($n.intVal) of nnkFloatLit..nnkFloat64Lit: res.add($n.floatVal) From b2060acbc49ccface03a2350bf1c2e9ad456a75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Mon, 16 Apr 2018 20:02:26 +0200 Subject: [PATCH 004/214] osproc: fix double close on POSIX (#5724) Calling close() in some cases issued two close() syscalls to one FD, which is incorrect in multithreaded programs. --- lib/pure/osproc.nim | 20 ++++++++++++++------ tests/osproc/tclose.nim | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 tests/osproc/tclose.nim diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 555626514a..a51b1f5ab5 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1001,13 +1001,21 @@ elif not defined(useNimRtl): {.pop} proc close(p: Process) = - if p.inStream != nil: close(p.inStream) - if p.outStream != nil: close(p.outStream) - if p.errStream != nil: close(p.errStream) if poParentStreams notin p.options: - discard close(p.inHandle) - discard close(p.outHandle) - discard close(p.errHandle) + if p.inStream != nil: + close(p.inStream) + else: + discard close(p.inHandle) + + if p.outStream != nil: + close(p.outStream) + else: + discard close(p.outHandle) + + if p.errStream != nil: + close(p.errStream) + else: + discard close(p.errHandle) proc suspend(p: Process) = if kill(p.id, SIGSTOP) != 0'i32: raiseOsError(osLastError()) diff --git a/tests/osproc/tclose.nim b/tests/osproc/tclose.nim new file mode 100644 index 0000000000..d466b466a7 --- /dev/null +++ b/tests/osproc/tclose.nim @@ -0,0 +1,24 @@ +discard """ + exitcode: 0 +""" + +when defined(linux): + import osproc, os + + proc countFds(): int = + result = 0 + for i in walkDir("/proc/self/fd"): + result += 1 + + let initCount = countFds() + + let p = osproc.startProcess("echo", options={poUsePath}) + assert countFds() == initCount + 3 + p.close + assert countFds() == initCount + + let p1 = osproc.startProcess("echo", options={poUsePath}) + discard p1.inputStream + assert countFds() == initCount + 3 + p.close + assert countFds() == initCount From 38b2596ff9935e417df6165038c59840352e6a60 Mon Sep 17 00:00:00 2001 From: hlaaf Date: Mon, 16 Apr 2018 22:01:37 +0300 Subject: [PATCH 005/214] Add none[T]() as alias to none(T) (#7512) * Add none[T]() as alias to none(T) * Add tests for none[T] * this test shouldn't work anyway --- lib/pure/options.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 8a771be719..aaffb57caa 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -104,6 +104,10 @@ proc none*(T: typedesc): Option[T] = # the default is the none type discard +proc none*[T]: Option[T] = + ## Alias for ``none(T)``. + none(T) + proc isSome*[T](self: Option[T]): bool {.inline.} = when T is SomePointer: self.val != nil @@ -290,3 +294,7 @@ when isMainModule: let tmp = option(intref) check(sizeof(tmp) == sizeof(ptr int)) + + test "none[T]": + check(none[int]().isNone) + check(none(int) == none[int]()) From c4d7cc3da0e127b54deb29fa70e225ffa1899dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Mon, 16 Apr 2018 21:52:27 +0200 Subject: [PATCH 006/214] Generate populationCount const at compile time (#7583) --- compiler/bitsets.nim | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/compiler/bitsets.nim b/compiler/bitsets.nim index 6afd1bd780..e387328774 100644 --- a/compiler/bitsets.nim +++ b/compiler/bitsets.nim @@ -72,24 +72,25 @@ proc bitSetContains(x, y: TBitSet): bool = result = true # Number of set bits for all values of int8 -const populationCount: array[low(int8)..high(int8), int8] = [ - 1.int8, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7 -] +const populationCount: array[low(int8)..high(int8), int8] = block: + var arr: array[low(int8)..high(int8), int8] + + proc countSetBits(x: int8): int8 = + return + ( x and 0b00000001'i8) + + ((x and 0b00000010'i8) shr 1) + + ((x and 0b00000100'i8) shr 2) + + ((x and 0b00001000'i8) shr 3) + + ((x and 0b00010000'i8) shr 4) + + ((x and 0b00100000'i8) shr 5) + + ((x and 0b01000000'i8) shr 6) + + ((x and 0b10000000'i8) shr 7) + + + for it in low(int8)..high(int8): + arr[it] = countSetBits(it) + + arr proc bitSetCard(x: TBitSet): BiggestInt = for it in x: From b1b517128e9ab4d1c1e8e16543008cbdecef0468 Mon Sep 17 00:00:00 2001 From: Hendrik Date: Mon, 16 Apr 2018 22:03:24 +0200 Subject: [PATCH 007/214] os.setLastModificationTime*(file: string, t: times.Time) (#7543) * add proc toFILETIME to winlean * add proc toWinTime to times * add proc setFileTime to winlean * openHandle with write access * add proc setLastModificationTime to os * moved epochDiff,rateDiff constants and proc toWinTime The constants were moved out of the when defined(JS) block so that they are alsways available in proc toWinTime. proc toWinTime was moved above the # Deprecated procs comment. Best new location seemed to be with the toUnix proc. --- lib/pure/os.nim | 22 +++++++++++++++++++--- lib/pure/times.nim | 8 +++++--- lib/windows/winlean.nim | 11 +++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index a77bee99da..255a9a8ded 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -329,20 +329,21 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", c_free(cast[pointer](r)) when defined(Windows): - proc openHandle(path: string, followSymlink=true): Handle = + proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle = var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL if not followSymlink: flags = flags or FILE_FLAG_OPEN_REPARSE_POINT + let access = if writeAccess: GENERIC_WRITE else: 0'i32 when useWinUnicode: result = createFileW( - newWideCString(path), 0'i32, + newWideCString(path), access, FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, flags, 0 ) else: result = createFileA( - path, 0'i32, + path, access, FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, flags, 0 ) @@ -1654,3 +1655,18 @@ proc isHidden*(path: string): bool = result = (fileName[0] == '.') and (fileName[3] != '.') {.pop.} + +proc setLastModificationTime*(file: string, t: times.Time) = + ## Sets the `file`'s last modification time. `OSError` is raised in case of + ## an error. + when defined(posix): + let unixt = t.toUnix.int + var timevals = [Timeval(tv_sec: unixt), Timeval(tv_sec: unixt)] # [last access, last modification] + if utimes(file, timevals.addr) != 0: raiseOSError(osLastError()) + else: + let h = openHandle(path = file, writeAccess = true) + if h == INVALID_HANDLE_VALUE: raiseOSError(osLastError()) + var ft = t.toWinTime.toFILETIME + let res = setFileTime(h, nil, nil, ft.addr) + discard h.closeHandle + if res == 0'i32: raiseOSError(osLastError()) \ No newline at end of file diff --git a/lib/pure/times.nim b/lib/pure/times.nim index dc216477b0..673f0b030e 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -191,6 +191,7 @@ const secondsInHour = 60*60 secondsInDay = 60*60*24 minutesInHour = 60 + rateDiff = 10000000'i64 # 100 nsecs # The number of hectonanoseconds between 1601/01/01 (windows epoch) # and 1970/01/01 (unix epoch). epochDiff = 116444736000000000'i64 @@ -371,6 +372,10 @@ proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} = ## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``). t.seconds +proc toWinTime*(t: Time): int64 = + ## Convert ``t`` to a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``). + result = t.seconds * rateDiff + epochDiff + proc isLeapYear*(year: int): bool = ## Returns true if ``year`` is a leap year. year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0) @@ -1713,9 +1718,6 @@ when not defined(JS): var clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int - const - rateDiff = 10000000'i64 # 100 nsecs - proc unixTimeToWinTime*(time: CTime): int64 = ## converts a UNIX `Time` (``time_t``) to a Windows file time result = int64(time) * rateDiff + epochDiff diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index f403443967..62bc38da9e 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -1086,3 +1086,14 @@ proc ConvertThreadToFiberEx*(param: pointer, flags: int32): pointer {.stdcall, d proc DeleteFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.} proc SwitchToFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.} proc GetCurrentFiber*(): pointer {.stdcall, importc, header: "Windows.h".} + +proc toFILETIME*(t: int64): FILETIME = + ## Convert the Windows file time timestamp ``t`` to ``FILETIME``. + result = FILETIME(dwLowDateTime: cast[DWORD](t), dwHighDateTime: DWORD(t shr 32)) + +type + LPFILETIME* = ptr FILETIME + +proc setFileTime*(hFile: HANDLE, lpCreationTime: LPFILETIME, + lpLastAccessTime: LPFILETIME, lpLastWriteTime: LPFILETIME): WINBOOL + {.stdcall, dynlib: "kernel32", importc: "SetFileTime".} From 9d4fd1f1bbc0d8a2327699dd07283260d85a5245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Tue, 17 Apr 2018 01:23:38 +0200 Subject: [PATCH 008/214] eqIdent new returns false on non identifier types (#7629) --- compiler/vm.nim | 18 +++++++++++++----- tests/macros/tmacro1.nim | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 09226988a6..5ef782abde 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1397,8 +1397,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let bNode = regs[rc].node # these are cstring to prevent string copy, and cmpIgnoreStyle from # takes cstring arguments - var aStrVal: cstring - var bStrVal: cstring + var aStrVal: cstring = nil + var bStrVal: cstring = nil # extract strVal from argument ``a`` case aNode.kind of {nkStrLit..nkTripleStrLit}: @@ -1407,8 +1407,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = aStrVal = aNode.ident.s.cstring of nkSym: aStrVal = aNode.sym.name.s.cstring + of nkOpenSymChoice, nkClosedSymChoice: + aStrVal = aNode[0].sym.name.s.cstring else: - stackTrace(c, tos, pc, errFieldXNotFound, "strVal") + discard # extract strVal from argument ``b`` case bNode.kind of {nkStrLit..nkTripleStrLit}: @@ -1417,11 +1419,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = bStrVal = bNode.ident.s.cstring of nkSym: bStrVal = bNode.sym.name.s.cstring + of nkOpenSymChoice, nkClosedSymChoice: + bStrVal = bNode[0].sym.name.s.cstring else: - stackTrace(c, tos, pc, errFieldXNotFound, "strVal") + discard # set result regs[ra].intVal = - ord(idents.cmpIgnoreStyle(aStrVal,bStrVal,high(int)) == 0) + if aStrVal != nil and bStrVal != nil: + ord(idents.cmpIgnoreStyle(aStrVal,bStrVal,high(int)) == 0) + else: + 0 + of opcStrToIdent: decodeB(rkNode) if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}: diff --git a/tests/macros/tmacro1.nim b/tests/macros/tmacro1.nim index 0b83345a14..ac2bf90945 100644 --- a/tests/macros/tmacro1.nim +++ b/tests/macros/tmacro1.nim @@ -27,11 +27,19 @@ import strutils template assertNot(arg: untyped): untyped = assert(not(arg)) + +proc foo(arg: int): void = + discard + +proc foo(arg: float): void = + discard + static: ## test eqIdent let a = "abc_def" let b = "abcDef" let c = "AbcDef" + let d = nnkBracketExpr.newTree() # not an identifier at all assert eqIdent( a , b ) assert eqIdent(newIdentNode(a), b ) @@ -62,3 +70,12 @@ static: assertNot eqIdent(genSym(nskLet, c), newIdentNode( b)) assertNot eqIdent(newIdentNode( c), genSym(nskLet, b)) assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b)) + + # eqIdent on non identifier at all + assertNot eqIdent(a,d) + + # eqIdent on sym choice + let fooSym = bindSym"foo" + assert fooSym.kind in {nnkOpenSymChoice, nnkClosedSymChoice} + assert fooSym.eqIdent("fOO") + assertNot fooSym.eqIdent("bar") From a708fda733cb6605ef122ac3be44df59929a6473 Mon Sep 17 00:00:00 2001 From: skilchen Date: Wed, 18 Apr 2018 13:22:05 +0200 Subject: [PATCH 009/214] allow stringification of DurationZero (#7625) --- lib/pure/times.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 673f0b030e..29492379d4 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -353,7 +353,9 @@ proc `$`*(dur: Duration): string = parts.add $quantity & " " & unitStrings[unit] & "s" result = "" - if parts.len == 1: + if parts.len == 0: + result.add "0 nanoseconds" + elif parts.len == 1: result = parts[0] elif parts.len == 2: result = parts[0] & " and " & parts[1] From 35b0cc67e89a929270e77c07ecbf06f7cced3668 Mon Sep 17 00:00:00 2001 From: treeform Date: Wed, 18 Apr 2018 11:40:11 -0700 Subject: [PATCH 010/214] Remove PHP backend. (#7606) * remove php * fix * keep nimphpext * remove targetJS enum --- compiler/jsgen.nim | 562 ++++++++++--------------------------- compiler/jstypes.nim | 19 -- compiler/lambdalifting.nim | 4 +- compiler/main.nim | 4 - compiler/nim.nim | 8 - compiler/options.nim | 1 - compiler/rodread.nim | 2 +- lib/system.nim | 21 +- lib/system/jssys.nim | 487 +++++++++++--------------------- 9 files changed, 330 insertions(+), 778 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index da5267b93b..4755089463 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -8,7 +8,6 @@ # # This is the JavaScript code generator. -# Also a PHP code generator. ;-) discard """ The JS code generator contains only 2 tricks: @@ -38,11 +37,8 @@ import from modulegraphs import ModuleGraph type - TTarget = enum - targetJS, targetPHP TJSGen = object of TPassContext module: PSym - target: TTarget sigConflicts: CountTable[SigHash] BModule = ref TJSGen @@ -92,16 +88,12 @@ type module: BModule g: PGlobals beforeRetNeeded: bool - target: TTarget # duplicated here for faster dispatching unique: int # for temp identifier generation blocks: seq[TBlock] extraIndent: int up: PProc # up the call chain; required for closure support declaredGlobals: IntSet -template `|`(a, b: untyped): untyped {.dirty.} = - (if p.target == targetJS: a else: b) - var indent = "\t".rope proc indentLine(p: PProc, r: Rope): Rope = @@ -157,11 +149,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode, module: module, procDef: procDef, g: globals, - target: module.target, extraIndent: int(procDef != nil)) if procDef != nil: result.prc = procDef.sons[namePos].sym - if result.target == targetPHP: - result.declaredGlobals = initIntSet() proc declareGlobal(p: PProc; id: int; r: Rope) = if p.prc != nil and not p.declaredGlobals.containsOrIncl(id): @@ -208,8 +197,7 @@ proc mapType(typ: PType): TJSTypeKind = of tyUnused, tyOptAsRef: internalError("mapType") proc mapType(p: PProc; typ: PType): TJSTypeKind = - if p.target == targetPHP: result = etyObject - else: result = mapType(typ) + result = mapType(typ) proc mangleName(m: BModule, s: PSym): Rope = proc validJsName(name: string): bool = @@ -236,7 +224,7 @@ proc mangleName(m: BModule, s: PSym): Rope = if result == nil: if s.kind == skField and s.name.s.validJsName: result = rope(s.name.s) - elif m.target == targetJS or s.kind == skTemp: + elif s.kind == skTemp: result = rope(mangle(s.name.s)) else: var x = newStringOfCap(s.name.s.len) @@ -314,7 +302,7 @@ proc useMagic(p: PProc, name: string) = proc isSimpleExpr(p: PProc; n: PNode): bool = # calls all the way down --> can stay expression based if n.kind in nkCallKinds+{nkBracketExpr, nkDotExpr, nkPar, nkTupleConstr} or - (p.target == targetJS and n.kind in {nkObjConstr, nkBracket, nkCurly}): + (n.kind in {nkObjConstr, nkBracket, nkCurly}): for c in n: if not p.isSimpleExpr(c): return false result = true @@ -323,12 +311,9 @@ proc isSimpleExpr(p: PProc; n: PNode): bool = proc getTemp(p: PProc, defineInLocals: bool = true): Rope = inc(p.unique) - if p.target == targetJS: - result = "Tmp$1" % [rope(p.unique)] - if defineInLocals: - add(p.locals, p.indentLine("var $1;$n" % [result])) - else: - result = "$$Tmp$1" % [rope(p.unique)] + result = "Tmp$1" % [rope(p.unique)] + if defineInLocals: + add(p.locals, p.indentLine("var $1;$n" % [result])) proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) = assert r.kind == resNone @@ -477,15 +462,9 @@ proc unsignedTrimmerJS(size: BiggestInt): Rope = of 4: rope">>> 0" else: rope"" -proc unsignedTrimmerPHP(size: BiggestInt): Rope = - case size - of 1: rope"& 0xff" - of 2: rope"& 0xffff" - of 4: rope"& 0xffffffff" - else: rope"" template unsignedTrimmer(size: BiggestInt): Rope = - size.unsignedTrimmerJS | size.unsignedTrimmerPHP + size.unsignedTrimmerJS proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, reassign = false) = @@ -533,46 +512,18 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mMulU: binaryUintExpr(p, n, r, "*") of mDivU: binaryUintExpr(p, n, r, "/") of mDivI: - if p.target == targetPHP: - var x, y: TCompRes - gen(p, n.sons[1], x) - gen(p, n.sons[2], y) - r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc] - else: - arithAux(p, n, r, op) + arithAux(p, n, r, op) of mModI: - if p.target == targetPHP: - var x, y: TCompRes - gen(p, n.sons[1], x) - gen(p, n.sons[2], y) - r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc] - else: - arithAux(p, n, r, op) + arithAux(p, n, r, op) of mShrI: var x, y: TCompRes gen(p, n.sons[1], x) gen(p, n.sons[2], y) let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size) - if p.target == targetPHP: - # XXX prevent multi evaluations - r.res = "(($1 $2) >= 0) ? (($1 $2) >> $3) : ((($1 $2) & 0x7fffffff) >> $3) | (0x40000000 >> ($3 - 1))" % [x.rdLoc, trimmer, y.rdLoc] - else: - r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc] + r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc] of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr: - if p.target == targetPHP: - if op == mEnumToStr: - var x: TCompRes - gen(p, n.sons[1], x) - r.res = "$#[$#]" % [genEnumInfoPHP(p, n.sons[1].typ), x.rdLoc] - elif op == mCharToStr: - var x: TCompRes - gen(p, n.sons[1], x) - r.res = "chr($#)" % [x.rdLoc] - else: - gen(p, n.sons[1], r) - else: - arithAux(p, n, r, op) + arithAux(p, n, r, op) else: arithAux(p, n, r, op) r.kind = resExpr @@ -591,7 +542,7 @@ proc genLineDir(p: PProc, n: PNode) = useMagic(p, "endb") lineF(p, "endb($1);$n", [rope(line)]) elif hasFrameInfo(p): - lineF(p, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)]) + lineF(p, "F.line = $1;$n", [rope(line)]) proc genWhileStmt(p: PProc, n: PNode) = var @@ -604,12 +555,12 @@ proc genWhileStmt(p: PProc, n: PNode) = p.blocks[length].id = -p.unique p.blocks[length].isLoop = true let labl = p.unique.rope - lineF(p, "L$1: while (true) {$n" | "while (true) {$n", [labl]) + lineF(p, "L$1: while (true) {$n", [labl]) p.nested: gen(p, n.sons[0], cond) - lineF(p, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n", + lineF(p, "if (!$1) break L$2;$n", [cond.res, labl]) p.nested: genStmt(p, n.sons[1]) - lineF(p, "}$n" | "}L$#:;$n", [labl]) + lineF(p, "}$n", [labl]) setLen(p.blocks, length) proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) = @@ -653,26 +604,22 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = var i = 1 var length = sonsLen(n) var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch - if catchBranchesExist and p.target == targetJS: + if catchBranchesExist: add(p.body, "++excHandler;" & tnl) var tmpFramePtr = rope"F" if optStackTrace notin p.options: tmpFramePtr = p.getTemp(true) line(p, tmpFramePtr & " = framePtr;" & tnl) lineF(p, "try {$n", []) - if p.target == targetPHP and p.globals == nil: - p.globals = "global $lastJSError; global $prevJSError;".rope var a: TCompRes gen(p, n.sons[0], a) moveInto(p, a, r) var generalCatchBranchExists = false - let dollar = rope(if p.target == targetJS: "" else: "$") - if p.target == targetJS and catchBranchesExist: + let dollar = rope("") + if catchBranchesExist: addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" & " lastJSError = EXC;$n --excHandler;$n", []) line(p, "framePtr = $1;$n" % [tmpFramePtr]) - elif p.target == targetPHP: - lineF(p, "} catch (Exception $$EXC) {$n $$prevJSError = $$lastJSError;$n $$lastJSError = $$EXC;$n", []) while i < length and n.sons[i].kind == nkExceptBranch: let blen = sonsLen(n.sons[i]) if blen == 1: @@ -704,19 +651,11 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = line(p, indent & "reraiseException();" & tnl) line(p, "}" & tnl) addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar]) - if p.target == targetJS: - line(p, "} finally {" & tnl) - line(p, "framePtr = $1;$n" % [tmpFramePtr]) - if p.target == targetPHP: - # XXX ugly hack for PHP codegen - line(p, "}" & tnl) + line(p, "} finally {" & tnl) + line(p, "framePtr = $1;$n" % [tmpFramePtr]) if i < length and n.sons[i].kind == nkFinally: genStmt(p, n.sons[i].sons[0]) - if p.target == targetPHP: - # XXX ugly hack for PHP codegen - line(p, "if($lastJSError) throw($lastJSError);" & tnl) - if p.target == targetJS: - line(p, "}" & tnl) + line(p, "}" & tnl) proc genRaiseStmt(p: PProc, n: PNode) = genLineDir(p, n) @@ -737,7 +676,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = genLineDir(p, n) gen(p, n.sons[0], cond) let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString - if stringSwitch and p.target == targetJS: + if stringSwitch: useMagic(p, "toJSStr") lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc]) else: @@ -789,12 +728,12 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) = sym.loc.k = locOther sym.position = idx+1 let labl = p.unique - lineF(p, "L$1: do {$n" | "", [labl.rope]) + lineF(p, "L$1: do {$n", [labl.rope]) setLen(p.blocks, idx + 1) p.blocks[idx].id = - p.unique # negative because it isn't used yet gen(p, n.sons[1], r) setLen(p.blocks, idx) - lineF(p, "} while(false);$n" | "$nL$#:;$n", [labl.rope]) + lineF(p, "} while(false);$n", [labl.rope]) proc genBreakStmt(p: PProc, n: PNode) = var idx: int @@ -812,7 +751,7 @@ proc genBreakStmt(p: PProc, n: PNode) = if idx < 0 or not p.blocks[idx].isLoop: internalError(n.info, "no loop to break") p.blocks[idx].id = abs(p.blocks[idx].id) # label is used - lineF(p, "break L$1;$n" | "goto L$1;$n", [rope(p.blocks[idx].id)]) + lineF(p, "break L$1;$n", [rope(p.blocks[idx].id)]) proc genAsmOrEmitStmt(p: PProc, n: PNode) = genLineDir(p, n) @@ -826,7 +765,6 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) = let v = it.sym # for backwards compatibility we don't deref syms here :-( if v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}: - if p.target == targetPHP: p.body.add "$" p.body.add mangleName(p.module, v) else: var r: TCompRes @@ -869,24 +807,11 @@ proc generateHeader(p: PProc, typ: PType): Rope = if isCompileTimeOnly(param.typ): continue if result != nil: add(result, ", ") var name = mangleName(p.module, param) - if p.target == targetJS: + add(result, name) + if mapType(param.typ) == etyBaseIndex: + add(result, ", ") add(result, name) - if mapType(param.typ) == etyBaseIndex: - add(result, ", ") - add(result, name) - add(result, "_Idx") - elif not (i == 1 and param.name.s == "this"): - let k = param.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind - if k in {tyVar, tyRef, tyPtr, tyLent, tyPointer}: - add(result, "&") - add(result, "$") - add(result, name) - # XXX I think something like this is needed for PHP to really support - # ptr "inside" strings and seq - #if mapType(param.typ) == etyBaseIndex: - # add(result, ", $") - # add(result, name) - # add(result, "_Idx") + add(result, "_Idx") proc countJsParams(typ: PType): int = for i in countup(1, sonsLen(typ.n) - 1): @@ -906,21 +831,10 @@ const proc needsNoCopy(p: PProc; y: PNode): bool = result = (y.kind in nodeKindsNeedNoCopy) or - (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyLent, tyVar}) or - p.target == targetPHP + (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyLent, tyVar}) proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = var a, b: TCompRes - - if p.target == targetPHP and x.kind == nkBracketExpr and - x[0].typ.skipTypes(abstractVar).kind in {tyString, tyCString}: - var c: TCompRes - gen(p, x[0], a) - gen(p, x[1], b) - gen(p, y, c) - lineF(p, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc]) - return - var xtyp = mapType(p, x.typ) if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject: @@ -968,7 +882,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = proc genAsgn(p: PProc, n: PNode) = genLineDir(p, n) - genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=p.target == targetPHP) + genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false) proc genFastAsgn(p: PProc, n: PNode) = genLineDir(p, n) @@ -991,12 +905,10 @@ proc genSwap(p: PProc, n: PNode) = let tmp2 = p.getTemp(false) if a.typ != etyBaseIndex or b.typ != etyBaseIndex: internalError(n.info, "genSwap") - lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n" | - "$1 = $2; $2 = $3; $3 = $1;$n", + lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n", [tmp, a.address, b.address]) tmp = tmp2 - lineF(p, "var $1 = $2; $2 = $3; $3 = $1;" | - "$1 = $2; $2 = $3; $3 = $1;", + lineF(p, "var $1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res]) proc getFieldPosition(f: PNode): int = @@ -1011,10 +923,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) = let b = if n.kind == nkHiddenAddr: n.sons[0] else: n gen(p, b.sons[0], a) if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple: - if p.target == targetJS: - r.res = makeJSString( "Field" & $getFieldPosition(b.sons[1]) ) - else: - r.res = getFieldPosition(b.sons[1]).rope + r.res = makeJSString("Field" & $getFieldPosition(b.sons[1])) else: if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr") var f = b.sons[1].sym @@ -1029,19 +938,13 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) = gen(p, n.sons[0], r) let otyp = skipTypes(n.sons[0].typ, abstractVarRange) if otyp.kind == tyTuple: - r.res = ("$1.Field$2" | "$1[$2]") % + r.res = ("$1.Field$2") % [r.res, getFieldPosition(n.sons[1]).rope] else: if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess") var f = n.sons[1].sym if f.loc.r == nil: f.loc.r = mangleName(p.module, f) - if p.target == targetJS: - r.res = "$1.$2" % [r.res, f.loc.r] - else: - if {sfImportc, sfExportc} * f.flags != {}: - r.res = "$1->$2" % [r.res, f.loc.r] - else: - r.res = "$1['$2']" % [r.res, f.loc.r] + r.res = "$1.$2" % [r.res, f.loc.r] r.kind = resExpr proc genAddr(p: PProc, n: PNode, r: var TCompRes) @@ -1069,13 +972,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = else: first = 0 if optBoundsCheck in p.options: useMagic(p, "chckIndx") - if p.target == targetPHP: - if typ.kind != tyString: - r.res = "chckIndx($1, $2, count($3)-1)-$2" % [b.res, rope(first), a.res] - else: - r.res = "chckIndx($1, $2, strlen($3))-$2" % [b.res, rope(first), a.res] - else: - r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), a.res] + r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), a.res] elif first != 0: r.res = "($1)-$2" % [b.res, rope(first)] else: @@ -1089,27 +986,11 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) = of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs: genArrayAddr(p, n, r) of tyTuple: - if p.target == targetPHP: - genFieldAccess(p, n, r) - return genFieldAddr(p, n, r) else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') r.typ = etyNone if r.res == nil: internalError(n.info, "genArrayAccess") - if p.target == targetPHP: - if n.sons[0].kind in nkCallKinds+{nkStrLit..nkTripleStrLit}: - useMagic(p, "nimAt") - if ty.kind in {tyString, tyCString}: - # XXX this needs to be more like substr($1,$2) - r.res = "ord(nimAt($1, $2))" % [r.address, r.res] - else: - r.res = "nimAt($1, $2)" % [r.address, r.res] - elif ty.kind in {tyString, tyCString}: - # XXX this needs to be more like substr($1,$2) - r.res = "ord(@$1[$2])" % [r.address, r.res] - else: - r.res = "$1[$2]" % [r.address, r.res] - elif ty.kind == tyCString: + if ty.kind == tyCString: r.res = "$1.charCodeAt($2)" % [r.address, r.res] else: r.res = "$1[$2]" % [r.address, r.res] @@ -1122,7 +1003,7 @@ template isIndirect(x: PSym): bool = #(mapType(v.typ) != etyObject) and {sfImportc, sfVolatile, sfExportc} * v.flags == {} and v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator, - skConst, skTemp, skLet} and p.target == targetJS) + skConst, skTemp, skLet}) proc genAddr(p: PProc, n: PNode, r: var TCompRes) = case n.sons[0].kind @@ -1138,8 +1019,6 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = r.typ = etyNone if isIndirect(s): r.res = s.loc.r & "[0]" - elif p.target == targetPHP: - r.res = "&" & s.loc.r else: r.res = s.loc.r r.address = nil @@ -1180,15 +1059,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind) proc thisParam(p: PProc; typ: PType): PType = - if p.target == targetPHP: - # XXX Might be very useful for the JS backend too? - let typ = skipTypes(typ, abstractInst) - assert(typ.kind == tyProc) - if 1 < sonsLen(typ.n): - assert(typ.n.sons[1].kind == nkSym) - let param = typ.n.sons[1].sym - if param.name.s == "this": - result = param.typ.skipTypes(abstractVar) + discard proc attachProc(p: PProc; content: Rope; s: PSym) = let otyp = thisParam(p, s.typ) @@ -1220,39 +1091,27 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = of skVar, skLet, skParam, skTemp, skResult, skForVar: if s.loc.r == nil: internalError(n.info, "symbol has no generated name: " & s.name.s) - if p.target == targetJS: - let k = mapType(p, s.typ) - if k == etyBaseIndex: - r.typ = etyBaseIndex - if {sfAddrTaken, sfGlobal} * s.flags != {}: - r.address = "$1[0]" % [s.loc.r] - r.res = "$1[1]" % [s.loc.r] - else: - r.address = s.loc.r - r.res = s.loc.r & "_Idx" - elif isIndirect(s): - r.res = "$1[0]" % [s.loc.r] + let k = mapType(p, s.typ) + if k == etyBaseIndex: + r.typ = etyBaseIndex + if {sfAddrTaken, sfGlobal} * s.flags != {}: + r.address = "$1[0]" % [s.loc.r] + r.res = "$1[1]" % [s.loc.r] else: - r.res = s.loc.r + r.address = s.loc.r + r.res = s.loc.r & "_Idx" + elif isIndirect(s): + r.res = "$1[0]" % [s.loc.r] else: - r.res = "$" & s.loc.r - if sfGlobal in s.flags: - p.declareGlobal(s.id, r.res) + r.res = s.loc.r of skConst: genConstant(p, s) if s.loc.r == nil: internalError(n.info, "symbol has no generated name: " & s.name.s) - if p.target == targetJS: - r.res = s.loc.r - else: - r.res = "$" & s.loc.r - p.declareGlobal(s.id, r.res) + r.res = s.loc.r of skProc, skFunc, skConverter, skMethod: discard mangleName(p.module, s) - if p.target == targetPHP and r.kind != resCallee: - r.res = makeJsString($s.loc.r) - else: - r.res = s.loc.r + r.res = s.loc.r if lfNoDecl in s.loc.flags or s.magic != mNone or {sfImportc, sfInfixCall} * s.flags != {}: discard @@ -1421,10 +1280,8 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = r.res = "$1[$2]" % [r.address, r.res] r.address = nil r.typ = etyNone - add(r.res, "." | "->") + add(r.res, ".") var op: TCompRes - if p.target == targetPHP: - op.kind = resCallee gen(p, n.sons[0], op) add(r.res, op.res) genArgs(p, n, r, 2) @@ -1433,28 +1290,21 @@ proc genCall(p: PProc, n: PNode, r: var TCompRes) = if n.sons[0].kind == nkSym and thisParam(p, n.sons[0].typ) != nil: genInfixCall(p, n, r) return - if p.target == targetPHP: - r.kind = resCallee gen(p, n.sons[0], r) genArgs(p, n, r) proc genEcho(p: PProc, n: PNode, r: var TCompRes) = let n = n[1].skipConv internalAssert n.kind == nkBracket - if p.target == targetJS: - useMagic(p, "toJSStr") # Used in rawEcho - useMagic(p, "rawEcho") - elif n.len == 0: - r.kind = resExpr - add(r.res, """print("\n")""") - return - add(r.res, "rawEcho(" | "print(") + useMagic(p, "toJSStr") # Used in rawEcho + useMagic(p, "rawEcho") + add(r.res, "rawEcho(") for i in countup(0, sonsLen(n) - 1): let it = n.sons[i] if it.typ.isCompileTimeOnly: continue - if i > 0: add(r.res, ", " | ".") + if i > 0: add(r.res, ", ") genArgNoParam(p, it, r) - add(r.res, ")" | """."\n")""") + add(r.res, ")") r.kind = resExpr proc putToSeq(s: string, indirect: bool): Rope = @@ -1474,10 +1324,7 @@ proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output: of nkSym: if rec.sym.id notin excludedFieldIDs: if output.len > 0: output.add(", ") - if p.target == targetJS: - output.addf("$#: ", [mangleName(p.module, rec.sym)]) - else: - output.addf("'$#' => ", [mangleName(p.module, rec.sym)]) + output.addf("$#: ", [mangleName(p.module, rec.sym)]) output.add(createVar(p, rec.sym.typ, false)) else: internalError(rec.info, "createRecordVarAux") @@ -1485,7 +1332,7 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v var t = typ if objHasTypeField(t): if output.len > 0: output.add(", ") - addf(output, "m_type: $1" | "'m_type' => $#", [genTypeInfo(p, t)]) + addf(output, "m_type: $1", [genTypeInfo(p, t)]) while t != nil: t = t.skipTypes(skipPtrs) createRecordVarAux(p, t.n, excludedFieldIDs, output) @@ -1514,49 +1361,42 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = of tyRange, tyGenericInst, tyAlias, tySink: result = createVar(p, lastSon(typ), indirect) of tySet: - result = putToSeq("{}" | "array()", indirect) + result = putToSeq("{}", indirect) of tyBool: result = putToSeq("false", indirect) of tyArray: let length = int(lengthOrd(t)) let e = elemType(t) let jsTyp = arrayTypeForElemType(e) - if not jsTyp.isNil and p.target == targetJS: + if not jsTyp.isNil: result = "new $1($2)" % [rope(jsTyp), rope(length)] elif length > 32: useMagic(p, "arrayConstr") # XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary. - if p.target == targetJS: useMagic(p, "nimCopy") + useMagic(p, "nimCopy") result = "arrayConstr($1, $2, $3)" % [rope(length), createVar(p, e, false), genTypeInfo(p, e)] else: - result = rope("[" | "array(") + result = rope("[") var i = 0 while i < length: if i > 0: add(result, ", ") add(result, createVar(p, e, false)) inc(i) - add(result, "]" | ")") + add(result, "]") if indirect: result = "[$1]" % [result] of tyTuple: - if p.target == targetJS: - result = rope("{") - for i in 0.. 0: add(result, ", ") - addf(result, "Field$1: $2", [i.rope, - createVar(p, t.sons[i], false)]) - add(result, "}") - if indirect: result = "[$1]" % [result] - else: - result = rope("array(") - for i in 0.. 0: add(result, ", ") - add(result, createVar(p, t.sons[i], false)) - add(result, ")") + result = rope("{") + for i in 0.. 0: add(result, ", ") + addf(result, "Field$1: $2", [i.rope, + createVar(p, t.sons[i], false)]) + add(result, "}") + if indirect: result = "[$1]" % [result] of tyObject: var initList: Rope createObjInitList(p, t, initIntSet(), initList) - result = ("{$1}" | "array($#)") % [initList] + result = ("{$1}") % [initList] if indirect: result = "[$1]" % [result] of tyVar, tyPtr, tyLent, tyRef: if mapType(p, t) == etyBaseIndex: @@ -1597,7 +1437,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = varCode = v.constraint.strVal if n.kind == nkEmpty: - lineF(p, varCode & " = $3;$n" | "$$$2 = $3;$n", + lineF(p, varCode & " = $3;$n", [returnType, varName, createVar(p, v.typ, isIndirect(v))]) if v.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and mapType(p, v.typ) == etyBaseIndex: lineF(p, "var $1_Idx = 0;$n", [varName]) @@ -1632,7 +1472,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = if isIndirect(v): lineF(p, varCode & " = [$3];$n", [returnType, v.loc.r, s]) else: - lineF(p, varCode & " = $3;$n" | "$$$2 = $3;$n", [returnType, v.loc.r, s]) + lineF(p, varCode & " = $3;$n", [returnType, v.loc.r, s]) if useReloadingGuard: lineF(p, "}$n") @@ -1665,18 +1505,14 @@ proc genNew(p: PProc, n: PNode) = var a: TCompRes gen(p, n.sons[1], a) var t = skipTypes(n.sons[1].typ, abstractVar).sons[0] - if p.target == targetJS: - lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)]) - else: - lineF(p, "$3 = $2; $1 = &$3;$n", [a.res, createVar(p, t, false), getTemp(p)]) + lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)]) proc genNewSeq(p: PProc, n: PNode) = var x, y: TCompRes gen(p, n.sons[1], x) gen(p, n.sons[2], y) let t = skipTypes(n.sons[1].typ, abstractVar).sons[0] - lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" | - "$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$3;}", [ + lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [ x.rdLoc, y.rdLoc, createVar(p, t, false)]) proc genOrd(p: PProc, n: PNode, r: var TCompRes) = @@ -1708,21 +1544,6 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) = else: r.res.add("$1)" % [a.res]) -proc genConStrStrPHP(p: PProc, n: PNode, r: var TCompRes) = - var a: TCompRes - gen(p, n.sons[1], a) - r.kind = resExpr - if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar: - r.res.add("chr($1)" % [a.res]) - else: - r.res.add(a.res) - for i in countup(2, sonsLen(n) - 1): - gen(p, n.sons[i], a) - if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar: - r.res.add(".chr($1)" % [a.res]) - else: - r.res.add(".$1" % [a.res]) - proc genToArray(p: PProc; n: PNode; r: var TCompRes) = # we map mArray to PHP's array constructor, a mild hack: var a, b: TCompRes @@ -1766,9 +1587,6 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = add(r.res, ")") proc genRepr(p: PProc, n: PNode, r: var TCompRes) = - if p.target == targetPHP: - localError(n.info, "'repr' not available for PHP backend") - return let t = skipTypes(n.sons[1].typ, abstractVarRange) case t.kind: of tyInt..tyInt64, tyUInt..tyUInt64: @@ -1828,57 +1646,36 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1") else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)") of mAppendStrCh: - if p.target == targetJS: - binaryExpr(p, n, r, "addChar", - "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }") - else: - binaryExpr(p, n, r, "", "$1 .= chr($2)") + binaryExpr(p, n, r, "addChar", + "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }") of mAppendStrStr: - if p.target == targetJS: - if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString: - binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }") - else: - binaryExpr(p, n, r, "", - "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}") - # XXX: make a copy of $2, because of Javascript's sucking semantics + if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString: + binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }") else: - binaryExpr(p, n, r, "", "$1 .= $2;") + binaryExpr(p, n, r, "", + "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}") + # XXX: make a copy of $2, because of Javascript's sucking semantics of mAppendSeqElem: - if p.target == targetJS: - var x, y: TCompRes - gen(p, n.sons[1], x) - gen(p, n.sons[2], y) - if needsNoCopy(p, n[2]): - r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, y.rdLoc] - else: - useMagic(p, "nimCopy") - let c = getTemp(p, defineInLocals=false) - lineF(p, "var $1 = nimCopy(null, $2, $3);$n", - [c, y.rdLoc, genTypeInfo(p, n[2].typ)]) - r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, c] - r.kind = resExpr + var x, y: TCompRes + gen(p, n.sons[1], x) + gen(p, n.sons[2], y) + if needsNoCopy(p, n[2]): + r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, y.rdLoc] else: - binaryExpr(p, n, r, "", "$1[] = $2") + useMagic(p, "nimCopy") + let c = getTemp(p, defineInLocals=false) + lineF(p, "var $1 = nimCopy(null, $2, $3);$n", + [c, y.rdLoc, genTypeInfo(p, n[2].typ)]) + r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, c] + r.kind = resExpr of mConStrStr: - if p.target == targetJS: - genConStrStr(p, n, r) - else: - genConStrStrPHP(p, n, r) + genConStrStr(p, n, r) of mEqStr: - if p.target == targetJS: - binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)") - else: - binaryExpr(p, n, r, "", "($1 == $2)") + binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)") of mLeStr: - if p.target == targetJS: - binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)") - else: - binaryExpr(p, n, r, "", "($1 <= $2)") + binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)") of mLtStr: - if p.target == targetJS: - binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)") - else: - binaryExpr(p, n, r, "", "($1 < $2)") + binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)") of mIsNil: unaryExpr(p, n, r, "", "($1 === null)") of mEnumToStr: genRepr(p, n, r) of mNew, mNewFinalize: genNew(p, n) @@ -1886,24 +1683,20 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do of mOrd: genOrd(p, n, r) of mLengthStr: - if p.target == targetJS and n.sons[1].typ.skipTypes(abstractInst).kind == tyCString: + if n.sons[1].typ.skipTypes(abstractInst).kind == tyCString: unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)") else: - unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)" | - "strlen($1)") - of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1" | "strlen($1)") + unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)") + of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1") of mLengthSeq, mLengthOpenArray, mLengthArray: - unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)" | - "count($1)") + unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)") of mXLenSeq: - unaryExpr(p, n, r, "", "$1.length" | "count($1)") + unaryExpr(p, n, r, "", "$1.length") of mHigh: if skipTypes(n.sons[1].typ, abstractVar).kind == tyString: - unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)" | - "(strlen($1)-1)") + unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)") else: - unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)" | - "(count($1)-1)") + unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)") of mInc: if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64: binaryUintExpr(p, n, r, "+", true) @@ -1917,7 +1710,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)") of mSetLengthStr: - binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "$1 = substr($1, 0, $2)") + binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0") of mSetLengthSeq: var x, y: TCompRes gen(p, n.sons[1], x) @@ -1934,50 +1727,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mPlusSet: binaryExpr(p, n, r, "SetPlus", "SetPlus($1, $2)") of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)") of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true") - of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]" | "unset $1[$2]") + of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]") of mInSet: - if p.target == targetJS: - binaryExpr(p, n, r, "", "($1[$2] != undefined)") - else: - let s = n.sons[1] - if s.kind == nkCurly: - var a, b, x: TCompRes - gen(p, n.sons[2], x) - r.res = rope("(") - r.kind = resExpr - for i in countup(0, sonsLen(s) - 1): - if i > 0: add(r.res, " || ") - var it = s.sons[i] - if it.kind == nkRange: - gen(p, it.sons[0], a) - gen(p, it.sons[1], b) - addf(r.res, "($1 >= $2 && $1 <= $3)", [x.res, a.res, b.res,]) - else: - gen(p, it, a) - addf(r.res, "($1 == $2)", [x.res, a.res]) - add(r.res, ")") - else: - binaryExpr(p, n, r, "", "isset($1[$2])") + binaryExpr(p, n, r, "", "($1[$2] != undefined)") of mNewSeq: genNewSeq(p, n) - of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]" | "array()") + of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]") of mOf: genOf(p, n, r) of mReset: genReset(p, n) of mEcho: genEcho(p, n, r) of mNLen..mNError, mSlurp, mStaticExec: localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s) of mCopyStr: - binaryExpr(p, n, r, "", "($1.slice($2))" | "substr($1, $2)") + binaryExpr(p, n, r, "", "($1.slice($2))") of mCopyStrLast: - if p.target == targetJS: - ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))") - else: - ternaryExpr(p, n, r, "nimSubstr", "nimSubstr($#, $#, $#)") + ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))") of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)") of mNewStringOfCap: - if p.target == targetJS: - unaryExpr(p, n, r, "mnewString", "mnewString(0)") - else: - unaryExpr(p, n, r, "", "''") + unaryExpr(p, n, r, "mnewString", "mnewString(0)") of mDotDot: genProcForSymIfNeeded(p, n.sons[0].sym) genCall(p, n, r) @@ -1985,8 +1751,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = useMagic(p, "nimParseBiggestFloat") genCall(p, n, r) of mArray: - if p.target == targetPHP: genToArray(p, n, r) - else: genCall(p, n, r) + genCall(p, n, r) else: genCall(p, n, r) #else internalError(e.info, 'genMagic: ' + magicToStr[op]); @@ -2003,13 +1768,13 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = if it.kind == nkRange: gen(p, it.sons[0], a) gen(p, it.sons[1], b) - addf(r.res, "[$1, $2]" | "array($#,$#)", [a.res, b.res]) + addf(r.res, "[$1, $2]", [a.res, b.res]) else: gen(p, it, a) add(r.res, a.res) add(r.res, ")") # emit better code for constant sets: - if p.target == targetJS and isDeepConstExpr(n): + if isDeepConstExpr(n): inc(p.g.unique) let tmp = rope("ConstSet") & rope(p.g.unique) addf(p.g.constants, "var $1 = $2;$n", [tmp, r.res]) @@ -2017,25 +1782,25 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes - r.res = rope("[" | "array(") + r.res = rope("[") r.kind = resExpr for i in countup(0, sonsLen(n) - 1): if i > 0: add(r.res, ", ") gen(p, n.sons[i], a) add(r.res, a.res) - add(r.res, "]" | ")") + add(r.res, "]") proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes - r.res = rope("{" | "array(") + r.res = rope("{") r.kind = resExpr for i in countup(0, sonsLen(n) - 1): if i > 0: add(r.res, ", ") var it = n.sons[i] if it.kind == nkExprColonExpr: it = it.sons[1] gen(p, it, a) - addf(r.res, "Field$#: $#" | "$2", [i.rope, a.res]) - r.res.add("}" | ")") + addf(r.res, "Field$#: $#", [i.rope, a.res]) + r.res.add("}") proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -2059,10 +1824,10 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = else: useMagic(p, "nimCopy") a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)] - addf(initList, "$#: $#" | "'$#' => $#" , [f.loc.r, a.res]) + addf(initList, "$#: $#", [f.loc.r, a.res]) let t = skipTypes(n.typ, abstractInst + skipPtrs) createObjInitList(p, t, fieldIDs, initList) - r.res = ("{$1}" | "array($#)") % [initList] + r.res = ("{$1}") % [initList] proc genConv(p: PProc, n: PNode, r: var TCompRes) = var dest = skipTypes(n.typ, abstractVarRange) @@ -2125,18 +1890,17 @@ proc genReturnStmt(p: PProc, n: PNode) = genStmt(p, n.sons[0]) else: genLineDir(p, n) - lineF(p, "break BeforeRet;$n" | "goto BeforeRet;$n", []) + lineF(p, "break BeforeRet;$n", []) proc frameCreate(p: PProc; procname, filename: Rope): Rope = let frameFmt = - "var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" | - "global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n" + "var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" result = p.indentLine(frameFmt % [procname, filename]) - result.add p.indentLine(ropes.`%`("framePtr = F;$n" | "$$framePtr = &$$F;$n", [])) + result.add p.indentLine(ropes.`%`("framePtr = F;$n", [])) proc frameDestroy(p: PProc): Rope = - result = p.indentLine rope(("framePtr = F.prev;" | "$framePtr = $F['prev'];") & tnl) + result = p.indentLine rope(("framePtr = F.prev;") & tnl) proc genProcBody(p: PProc, prc: PSym): Rope = if hasFrameInfo(p): @@ -2146,15 +1910,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope = else: result = nil if p.beforeRetNeeded: - if p.target == targetJS: - result.add p.indentLine(~"BeforeRet: do {$n") - result.add p.body - result.add p.indentLine(~"} while (false);$n") - else: - addF(result, "$# BeforeRet:;$n", [p.body]) + result.add p.indentLine(~"BeforeRet: do {$n") + result.add p.body + result.add p.indentLine(~"} while (false);$n") else: add(result, p.body) - if prc.typ.callConv == ccSysCall and p.target == targetJS: + if prc.typ.callConv == ccSysCall: result = ("try {$n$1} catch (e) {$n" & " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}") % [result] if hasFrameInfo(p): @@ -2182,7 +1943,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = resultSym = prc.ast.sons[resultPos].sym let mname = mangleName(p.module, resultSym) let resVar = createVar(p, resultSym.typ, isIndirect(resultSym)) - resultAsgn = p.indentLine(("var $# = $#;$n" | "$$$# = $#;$n") % [mname, resVar]) + resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar]) if resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and mapType(p, resultSym.typ) == etyBaseIndex: resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname]) @@ -2267,8 +2028,7 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) = elif fromUint: if src.size == 4 and dest.size == 4: # XXX prevent multi evaluations - r.res = "($1|0)" % [r.res] | - "($1>(float)2147483647?(int)$1-4294967296:$1)" % [r.res] + r.res = "($1|0)" % [r.res] else: let trimmer = unsignedTrimmer(dest.size) let minuend = case dest.size @@ -2304,8 +2064,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = r.res = rope"null" r.kind = resExpr of nkStrLit..nkTripleStrLit: - if skipTypes(n.typ, abstractVarRange).kind == tyString and - p.target == targetJS: + if skipTypes(n.typ, abstractVarRange).kind == tyString: useMagic(p, "makeNimstrLit") r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)] else: @@ -2342,10 +2101,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkObjConstr: genObjConstr(p, n, r) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r) of nkAddr, nkHiddenAddr: - if p.target == targetJS: - genAddr(p, n, r) - else: - gen(p, n.sons[0], r) + genAddr(p, n, r) of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r) of nkBracketExpr: genArrayAccess(p, n, r) of nkDotExpr: genFieldAccess(p, n, r) @@ -2422,31 +2178,22 @@ proc newModule(module: PSym): BModule = if globals == nil: globals = newGlobals() -proc genHeader(target: TTarget): Rope = - if target == targetJS: - result = ( - "/* Generated by the Nim Compiler v$1 */$n" & - "/* (c) " & copyrightYear & " Andreas Rumpf */$n$n" & - "var framePtr = null;$n" & - "var excHandler = 0;$n" & - "var lastJSError = null;$n" & - "if (typeof Int8Array === 'undefined') Int8Array = Array;$n" & - "if (typeof Int16Array === 'undefined') Int16Array = Array;$n" & - "if (typeof Int32Array === 'undefined') Int32Array = Array;$n" & - "if (typeof Uint8Array === 'undefined') Uint8Array = Array;$n" & - "if (typeof Uint16Array === 'undefined') Uint16Array = Array;$n" & - "if (typeof Uint32Array === 'undefined') Uint32Array = Array;$n" & - "if (typeof Float32Array === 'undefined') Float32Array = Array;$n" & - "if (typeof Float64Array === 'undefined') Float64Array = Array;$n") % - [rope(VersionAsString)] - else: - result = (" 0: add(s, ", " & tnl) - let extName = if field.ast == nil: field.name.s else: field.ast.strVal - addf(s, "$# => $#$n", - [rope(field.position), makeJSString(extName)]) - prepend(p.g.typeInfo, "$$$# = $#;$n" % [result, s]) - proc genTypeInfo(p: PProc, typ: PType): Rope = - if p.target == targetPHP: - return makeJSString(typeToString(typ, preferModuleInfo)) let t = typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink}) result = "NTI$1" % [rope(t.id)] if containsOrIncl(p.g.typeInfoGenerated, t.id): return diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index d881df5e9a..7757484250 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -230,7 +230,7 @@ template isIterator*(owner: PSym): bool = proc liftingHarmful(owner: PSym): bool {.inline.} = ## lambda lifting can be harmful for JS-like code generators. let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro - result = gCmd in {cmdCompileToPHP, cmdCompileToJS} and not isCompileTime + result = gCmd == cmdCompileToJS and not isCompileTime proc liftIterSym*(n: PNode; owner: PSym): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) @@ -813,7 +813,7 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode = let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro if body.kind == nkEmpty or ( - gCmd in {cmdCompileToPHP, cmdCompileToJS} and not isCompileTime) or + gCmd == cmdCompileToJS and not isCompileTime) or fn.skipGenericOwner.kind != skModule: # ignore forward declaration: result = body diff --git a/compiler/main.nim b/compiler/main.nim index 20a7158864..c928c81cd0 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -94,7 +94,6 @@ proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) = defineSymbol("nimrod") # 'nimrod' is always defined defineSymbol("ecmascript") # For backward compatibility defineSymbol("js") - if gCmd == cmdCompileToPHP: defineSymbol("nimphp") semanticPasses() registerPass(JSgenPass) compileProject(graph, cache) @@ -189,9 +188,6 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = of "js", "compiletojs": gCmd = cmdCompileToJS commandCompileToJS(graph, cache) - of "php": - gCmd = cmdCompileToPHP - commandCompileToJS(graph, cache) of "doc0": wantMainModule() gCmd = cmdDoc diff --git a/compiler/nim.nim b/compiler/nim.nim index 89225a5e01..8f3463be98 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -90,14 +90,6 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = ex = quoteShell( completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir)) execExternalProgram(findNodeJs() & " " & ex & ' ' & commands.arguments) - elif gCmd == cmdCompileToPHP: - var ex: string - if options.outFile.len > 0: - ex = options.outFile.prependCurDir.quoteShell - else: - ex = quoteShell( - completeCFilePath(changeFileExt(gProjectFull, "php").prependCurDir)) - execExternalProgram("php " & ex & ' ' & commands.arguments) else: var binPath: string if options.outFile.len > 0: diff --git a/compiler/options.nim b/compiler/options.nim index 69a555b3fc..93a3f17962 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -81,7 +81,6 @@ type # **keep binary compatible** cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, - cmdCompileToPHP, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc, cmdGenDepend, cmdDump, cmdCheck, # semantic checking for whole project diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 84f175cb5d..4ada148c5e 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -586,7 +586,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool = # new command forces us to consider it here :-) case old of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, - cmdCompileToJS, cmdCompileToPHP, cmdCompileToLLVM: + cmdCompileToJS, cmdCompileToLLVM: if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef, cmdInteractive}: return false diff --git a/lib/system.nim b/lib/system.nim index 3761a35f8b..9f0b115973 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2404,7 +2404,7 @@ proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} = if x.isNil and y.isNil: return true else: - when not defined(JS) or defined(nimphp): + when not defined(JS): proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} = result = cast[pointer](x) else: @@ -2766,17 +2766,14 @@ type when defined(JS): proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = - when defined(nimphp): - asm """`x` .= `y`;""" - else: - asm """ - var len = `x`[0].length-1; - for (var i = 0; i < `y`.length; ++i) { - `x`[0][len] = `y`.charCodeAt(i); - ++len; - } - `x`[0][len] = 0 - """ + asm """ + var len = `x`[0].length-1; + for (var i = 0; i < `y`.length; ++i) { + `x`[0][len] = `y`.charCodeAt(i); + ++len; + } + `x`[0][len] = 0 + """ proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} elif hasAlloc: diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 8c3175eac4..56a9f65756 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -48,10 +48,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} = result[0] = x proc isNimException(): bool {.asmNoStackFrame.} = - when defined(nimphp): - asm "return isset(`lastJSError`['m_type']);" - else: - asm "return `lastJSError`.m_type;" + asm "return `lastJSError`.m_type;" proc getCurrentException*(): ref Exception {.compilerRtl, benign.} = if isNimException(): result = cast[ref Exception](lastJSError) @@ -61,15 +58,14 @@ proc getCurrentExceptionMsg*(): string = if isNimException(): return cast[Exception](lastJSError).msg else: - when not defined(nimphp): - var msg: cstring - {.emit: """ - if (`lastJSError`.message !== undefined) { - `msg` = `lastJSError`.message; - } - """.} - if not msg.isNil: - return $msg + var msg: cstring + {.emit: """ + if (`lastJSError`.message !== undefined) { + `msg` = `lastJSError`.message; + } + """.} + if not msg.isNil: + return $msg return "" proc auxWriteStackTrace(f: PCallFrame): string = @@ -140,12 +136,9 @@ proc raiseException(e: ref Exception, ename: cstring) {. e.name = ename if excHandler == 0: unhandledException(e) - when defined(nimphp): - asm """throw new Exception($`e`["message"]);""" - else: - when NimStackTrace: - e.trace = rawWriteStackTrace() - asm "throw `e`;" + when NimStackTrace: + e.trace = rawWriteStackTrace() + asm "throw `e`;" proc reraiseException() {.compilerproc, asmNoStackFrame.} = if lastJSError == nil: @@ -173,57 +166,35 @@ proc raiseFieldError(f: string) {.compilerproc, noreturn.} = raise newException(FieldError, f & " is not accessible") proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - $args = func_get_args(); - $result = array(); - foreach ($args as $x) { - if (is_array($x)) { - for ($j = $x[0]; $j <= $x[1]; $j++) { - $result[$j] = true; - } - } else { - $result[$x] = true; + asm """ + var result = {}; + for (var i = 0; i < arguments.length; ++i) { + var x = arguments[i]; + if (typeof(x) == "object") { + for (var j = x[0]; j <= x[1]; ++j) { + result[j] = true; } + } else { + result[x] = true; } - return $result; - """ - else: - asm """ - var result = {}; - for (var i = 0; i < arguments.length; ++i) { - var x = arguments[i]; - if (typeof(x) == "object") { - for (var j = x[0]; j <= x[1]; ++j) { - result[j] = true; - } - } else { - result[x] = true; - } - } - return result; - """ + } + return result; + """ proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - {.emit: """return `c`;""".} - else: - {.emit: """ - var ln = `c`.length; - var result = new Array(ln + 1); - var i = 0; - for (; i < ln; ++i) { - result[i] = `c`.charCodeAt(i); - } - result[i] = 0; // terminating zero - return result; - """.} + {.emit: """ + var ln = `c`.length; + var result = new Array(ln + 1); + var i = 0; + for (; i < ln; ++i) { + result[i] = `c`.charCodeAt(i); + } + result[i] = 0; // terminating zero + return result; + """.} proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - {.emit: """return `c`;""".} - else: - {.emit: """ + {.emit: """ var ln = `c`.length; var result = new Array(ln); var r = 0; @@ -261,156 +232,93 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} = """.} proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - {.emit: """return `s`;""".} - else: - asm """ - var len = `s`.length-1; - var asciiPart = new Array(len); - var fcc = String.fromCharCode; - var nonAsciiPart = null; - var nonAsciiOffset = 0; - for (var i = 0; i < len; ++i) { - if (nonAsciiPart !== null) { - var offset = (i - nonAsciiOffset) * 2; - var code = `s`[i].toString(16); - if (code.length == 1) { - code = "0"+code; - } - nonAsciiPart[offset] = "%"; - nonAsciiPart[offset + 1] = code; - } - else if (`s`[i] < 128) - asciiPart[i] = fcc(`s`[i]); - else { - asciiPart.length = i; - nonAsciiOffset = i; - nonAsciiPart = new Array((len - i) * 2); - --i; + asm """ + var len = `s`.length-1; + var asciiPart = new Array(len); + var fcc = String.fromCharCode; + var nonAsciiPart = null; + var nonAsciiOffset = 0; + for (var i = 0; i < len; ++i) { + if (nonAsciiPart !== null) { + var offset = (i - nonAsciiOffset) * 2; + var code = `s`[i].toString(16); + if (code.length == 1) { + code = "0"+code; } + nonAsciiPart[offset] = "%"; + nonAsciiPart[offset + 1] = code; } - asciiPart = asciiPart.join(""); - return (nonAsciiPart === null) ? - asciiPart : asciiPart + decodeURIComponent(nonAsciiPart.join("")); + else if (`s`[i] < 128) + asciiPart[i] = fcc(`s`[i]); + else { + asciiPart.length = i; + nonAsciiOffset = i; + nonAsciiPart = new Array((len - i) * 2); + --i; + } + } + asciiPart = asciiPart.join(""); + return (nonAsciiPart === null) ? + asciiPart : asciiPart + decodeURIComponent(nonAsciiPart.join("")); """ proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return str_repeat(chr(0),`len`); - """ - else: - asm """ - var result = new Array(`len`+1); - result[0] = 0; - result[`len`] = 0; - return result; - """ - -when defined(nimphp): - proc nimAt(x: string; i: int): string {.asmNoStackFrame, compilerproc.} = - asm """ - return `x`[`i`]; - """ - -when defined(nimphp): - proc nimSubstr(s: string; a, b: int): string {. - asmNoStackFrame, compilerproc.} = - asm """return substr(`s`,`a`,`b`-`a`+1);""" + asm """ + var result = new Array(`len`+1); + result[0] = 0; + result[`len`] = 0; + return result; + """ proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} = # argument type is a fake - when defined(nimphp): - asm """ - return count(`a`); - """ - else: - asm """ - var result = 0; - for (var elem in `a`) { ++result; } - return result; - """ + asm """ + var result = 0; + for (var elem in `a`) { ++result; } + return result; + """ proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} = - when defined(nimphp): - asm """ - foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; } - foreach (`b` as $elem=>$_) { if (!isset(`a`[$elem])) return false; } - return true; - """ - else: - asm """ - for (var elem in `a`) { if (!`b`[elem]) return false; } - for (var elem in `b`) { if (!`a`[elem]) return false; } - return true; - """ + asm """ + for (var elem in `a`) { if (!`b`[elem]) return false; } + for (var elem in `b`) { if (!`a`[elem]) return false; } + return true; + """ proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} = - when defined(nimphp): - asm """ - foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; } - return true; - """ - else: - asm """ - for (var elem in `a`) { if (!`b`[elem]) return false; } - return true; - """ + asm """ + for (var elem in `a`) { if (!`b`[elem]) return false; } + return true; + """ proc SetLt(a, b: int): bool {.compilerproc.} = result = SetLe(a, b) and not SetEq(a, b) proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} = - when defined(nimphp): - asm """ - var $result = array(); - foreach (`a` as $elem=>$_) { - if (isset(`b`[$elem])) { $result[$elem] = true; } - } - return $result; - """ - else: - asm """ - var result = {}; - for (var elem in `a`) { - if (`b`[elem]) { result[elem] = true; } - } - return result; - """ + asm """ + var result = {}; + for (var elem in `a`) { + if (`b`[elem]) { result[elem] = true; } + } + return result; + """ proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} = - when defined(nimphp): - asm """ - var $result = array(); - foreach (`a` as $elem=>$_) { $result[$elem] = true; } - foreach (`b` as $elem=>$_) { $result[$elem] = true; } - return $result; - """ - else: - asm """ - var result = {}; - for (var elem in `a`) { result[elem] = true; } - for (var elem in `b`) { result[elem] = true; } - return result; - """ + asm """ + var result = {}; + for (var elem in `a`) { result[elem] = true; } + for (var elem in `b`) { result[elem] = true; } + return result; + """ proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} = - when defined(nimphp): - asm """ - $result = array(); - foreach (`a` as $elem=>$_) { - if (!isset(`b`[$elem])) { $result[$elem] = true; } - } - return $result; - """ - else: - asm """ - var result = {}; - for (var elem in `a`) { - if (!`b`[elem]) { result[elem] = true; } - } - return result; - """ + asm """ + var result = {}; + for (var elem in `a`) { + if (!`b`[elem]) { result[elem] = true; } + } + return result; + """ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} = asm """ @@ -424,15 +332,8 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} = return `a`.length - `b`.length; """ -proc cmp(x, y: string): int = - when defined(nimphp): - asm """ - if(`x` < `y`) `result` = -1; - elseif (`x` > `y`) `result` = 1; - else `result` = 0; - """ - else: - return cmpStrings(x, y) +proc cmp(x, y: string): int = + return cmpStrings(x, y) proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} = asm """ @@ -467,7 +368,7 @@ elif not defined(nimOldEcho): console.log(buf); """ -elif not defined(nimphp): +else: proc ewriteln(x: cstring) = var node : JSRef {.emit: "`node` = document.getElementsByTagName('body')[0];".} @@ -493,127 +394,77 @@ elif not defined(nimphp): # Arithmetic: proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return `a` + `b`; - """ - else: - asm """ - var result = `a` + `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); - return result; - """ + asm """ + var result = `a` + `b`; + if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + return result; + """ proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return `a` - `b`; - """ - else: - asm """ - var result = `a` - `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); - return result; - """ + asm """ + var result = `a` - `b`; + if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + return result; + """ proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return `a` * `b`; - """ - else: - asm """ - var result = `a` * `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); - return result; - """ + asm """ + var result = `a` * `b`; + if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + return result; + """ proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return trunc(`a` / `b`); - """ - else: - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); - return Math.trunc(`a` / `b`); - """ + asm """ + if (`b` == 0) `raiseDivByZero`(); + if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); + return Math.trunc(`a` / `b`); + """ proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return `a` % `b`; - """ - else: - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); - return Math.trunc(`a` % `b`); - """ + asm """ + if (`b` == 0) `raiseDivByZero`(); + if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); + return Math.trunc(`a` % `b`); + """ proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return `a` + `b`; - """ - else: - asm """ - var result = `a` + `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); - return result; - """ + asm """ + var result = `a` + `b`; + if (result > 9223372036854775807 + || result < -9223372036854775808) `raiseOverflow`(); + return result; + """ proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return `a` - `b`; - """ - else: - asm """ - var result = `a` - `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); - return result; - """ + asm """ + var result = `a` - `b`; + if (result > 9223372036854775807 + || result < -9223372036854775808) `raiseOverflow`(); + return result; + """ proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return `a` * `b`; - """ - else: - asm """ - var result = `a` * `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); - return result; - """ + asm """ + var result = `a` * `b`; + if (result > 9223372036854775807 + || result < -9223372036854775808) `raiseOverflow`(); + return result; + """ proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return trunc(`a` / `b`); - """ - else: - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.trunc(`a` / `b`); - """ + asm """ + if (`b` == 0) `raiseDivByZero`(); + if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); + return Math.trunc(`a` / `b`); + """ proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - when defined(nimphp): - asm """ - return `a` % `b`; - """ - else: - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.trunc(`a` % `b`); - """ + asm """ + if (`b` == 0) `raiseDivByZero`(); + if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); + return Math.trunc(`a` % `b`); + """ proc negInt(a: int): int {.compilerproc.} = result = a*(-1) @@ -767,24 +618,14 @@ proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} = else: discard -when defined(nimphp): - proc arrayConstr(len: int, value: string, typ: string): JSRef {. - asmNoStackFrame, compilerproc.} = - # types are fake - asm """ - $result = array(); - for ($i = 0; $i < `len`; $i++) $result[] = `value`; - return $result; - """ -else: - proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {. - asmNoStackFrame, compilerproc.} = +proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {. + asmNoStackFrame, compilerproc.} = # types are fake - asm """ - var result = new Array(`len`); - for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`); - return result; - """ + asm """ + var result = new Array(`len`); + for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`); + return result; + """ proc chckIndx(i, a, b: int): int {.compilerproc.} = if i >= a and i <= b: return i From 0448d3f6ea3516bee9816320fefc62bc9c7d23fc Mon Sep 17 00:00:00 2001 From: genotrance Date: Wed, 18 Apr 2018 14:19:23 -0500 Subject: [PATCH 011/214] test case for #2416 (#7649) --- tests/template/i2416.nim | 1 + tests/template/t2416.nim | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 tests/template/i2416.nim create mode 100644 tests/template/t2416.nim diff --git a/tests/template/i2416.nim b/tests/template/i2416.nim new file mode 100644 index 0000000000..4b53cd0ca8 --- /dev/null +++ b/tests/template/i2416.nim @@ -0,0 +1 @@ +template i2416*() = echo "i2416" diff --git a/tests/template/t2416.nim b/tests/template/t2416.nim new file mode 100644 index 0000000000..f738807188 --- /dev/null +++ b/tests/template/t2416.nim @@ -0,0 +1,2 @@ +import i2416 +i2416() From b9cafe5752f0772b6c05b78c45cd72b8c0932de2 Mon Sep 17 00:00:00 2001 From: genotrance Date: Wed, 18 Apr 2018 14:19:48 -0500 Subject: [PATCH 012/214] test case for #1154 (#7648) --- tests/errmsgs/t1154.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/errmsgs/t1154.nim diff --git a/tests/errmsgs/t1154.nim b/tests/errmsgs/t1154.nim new file mode 100644 index 0000000000..7fcbf8a277 --- /dev/null +++ b/tests/errmsgs/t1154.nim @@ -0,0 +1,11 @@ +discard """ +errormsg: "invalid type: 'expr' in this context: 'proc (a: varargs[expr])' for proc" +line: 8 +""" + +import typetraits + +proc foo(a:varargs[expr]) = + echo a[0].type.name + +foo(1) From fdf1d123804df3325211384e1c438295ea23bbd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Wed, 18 Apr 2018 21:24:28 +0200 Subject: [PATCH 013/214] Change type of `Timeval.tv_sec` to `posix.Time` (#7646) --- changelog.md | 1 + lib/deprecated/pure/asyncio.nim | 12 ++++++++---- lib/deprecated/pure/sockets.nim | 8 ++++++-- lib/posix/posix_linux_amd64.nim | 4 ++-- lib/posix/posix_other.nim | 4 ++-- lib/pure/nativesockets.nim | 8 ++++++-- lib/pure/os.nim | 2 +- lib/pure/osproc.nim | 2 +- lib/pure/times.nim | 2 +- 9 files changed, 28 insertions(+), 15 deletions(-) diff --git a/changelog.md b/changelog.md index f39dc26785..e6d1f6b478 100644 --- a/changelog.md +++ b/changelog.md @@ -27,6 +27,7 @@ - ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type to ``times.Duration`` in order to support higher time resolutions. The proc is no longer deprecated. +- ``posix.Timeval.tv_sec`` has changed type to ``posix.Time``. #### Breaking changes in the compiler diff --git a/lib/deprecated/pure/asyncio.nim b/lib/deprecated/pure/asyncio.nim index 5fd45b2155..34cabefb06 100644 --- a/lib/deprecated/pure/asyncio.nim +++ b/lib/deprecated/pure/asyncio.nim @@ -101,8 +101,8 @@ when defined(windows): from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet, FD_ISSET, select else: - from posix import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet, - FD_ISSET, select + from posix import TimeVal, Time, Suseconds, SocketHandle, FD_SET, FD_ZERO, + TFdSet, FD_ISSET, select type DelegateObj* = object @@ -556,8 +556,12 @@ proc send*(sock: AsyncSocket, data: string) = proc timeValFromMilliseconds(timeout = 500): Timeval = if timeout != -1: var seconds = timeout div 1000 - result.tv_sec = seconds.int32 - result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 + when defined(posix): + result.tv_sec = seconds.Time + result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds + else: + result.tv_sec = seconds.int32 + result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) = FD_ZERO(fd) diff --git a/lib/deprecated/pure/sockets.nim b/lib/deprecated/pure/sockets.nim index f068c7d560..f0568366ab 100644 --- a/lib/deprecated/pure/sockets.nim +++ b/lib/deprecated/pure/sockets.nim @@ -953,8 +953,12 @@ when defined(ssl): proc timeValFromMilliseconds(timeout = 500): Timeval = if timeout != -1: var seconds = timeout div 1000 - result.tv_sec = seconds.int32 - result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 + when defined(posix): + result.tv_sec = seconds.Time + result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds + else: + result.tv_sec = seconds.int32 + result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 proc createFdSet(fd: var TFdSet, s: seq[Socket], m: var int) = FD_ZERO(fd) diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim index 9e6211b633..4f114d3949 100644 --- a/lib/posix/posix_linux_amd64.nim +++ b/lib/posix/posix_linux_amd64.nim @@ -351,8 +351,8 @@ type Timeval* {.importc: "struct timeval", header: "", final, pure.} = object ## struct timeval - tv_sec*: clong ## Seconds. - tv_usec*: clong ## Microseconds. + tv_sec*: Time ## Seconds. + tv_usec*: Suseconds ## Microseconds. TFdSet* {.importc: "fd_set", header: "", final, pure.} = object abi: array[1024 div (8 * sizeof(clong)), clong] diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 01bc1c1e5e..ae41263e81 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -335,8 +335,8 @@ type Timeval* {.importc: "struct timeval", header: "", final, pure.} = object ## struct timeval - tv_sec*: int ## Seconds. - tv_usec*: int ## Microseconds. + tv_sec*: Time ## Seconds. + tv_usec*: Suseconds ## Microseconds. TFdSet* {.importc: "fd_set", header: "", final, pure.} = object Mcontext* {.importc: "mcontext_t", header: "", diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 74b2c9741e..09fa253f12 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -616,8 +616,12 @@ proc setBlocking*(s: SocketHandle, blocking: bool) = proc timeValFromMilliseconds(timeout = 500): Timeval = if timeout != -1: var seconds = timeout div 1000 - result.tv_sec = seconds.int32 - result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 + when useWinVersion: + result.tv_sec = seconds.int32 + result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 + else: + result.tv_sec = seconds.Time + result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds proc createFdSet(fd: var TFdSet, s: seq[SocketHandle], m: var int) = FD_ZERO(fd) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 255a9a8ded..8298024d68 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1660,7 +1660,7 @@ proc setLastModificationTime*(file: string, t: times.Time) = ## Sets the `file`'s last modification time. `OSError` is raised in case of ## an error. when defined(posix): - let unixt = t.toUnix.int + let unixt = posix.Time(t.toUnix) var timevals = [Timeval(tv_sec: unixt), Timeval(tv_sec: unixt)] # [last access, last modification] if utimes(file, timevals.addr) != 0: raiseOSError(osLastError()) else: diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index a51b1f5ab5..bcab5ad3ae 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1289,7 +1289,7 @@ elif not defined(useNimRtl): proc select(readfds: var seq[Process], timeout = 500): int = var tv: Timeval - tv.tv_sec = 0 + tv.tv_sec = posix.Time(0) tv.tv_usec = timeout * 1000 var rd: TFdSet diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 29492379d4..cad32b51ac 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1752,7 +1752,7 @@ when not defined(JS): when defined(posix): var a: Timeval gettimeofday(a) - result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001 + result = toBiggestFloat(a.tv_sec.int64) + toFloat(a.tv_usec)*0.00_0001 elif defined(windows): var f: winlean.FILETIME getSystemTimeAsFileTime(f) From a230307b48f2cfa2fc2688ff5d706dbe9c5de154 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 12 Apr 2018 10:57:47 +0200 Subject: [PATCH 014/214] little progress on nimpretty --- compiler/lexer.nim | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index e55da2f35f..1d9279d02d 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -1003,6 +1003,10 @@ proc skip(L: var TLexer, tok: var TToken) = var buf = L.buf tokenBegin(tok, pos) tok.strongSpaceA = 0 + when defined(nimpretty): + var hasComment = false + tok.commentOffsetA = L.offsetBase + pos + tok.commentOffsetB = tok.commentOffsetA while true: case buf[pos] of ' ': @@ -1021,6 +1025,7 @@ proc skip(L: var TLexer, tok: var TToken) = inc(pos) inc(indent) elif buf[pos] == '#' and buf[pos+1] == '[': + when defined(nimpretty): hasComment = true skipMultiLineComment(L, tok, pos+2, false) pos = L.bufpos buf = L.buf @@ -1034,14 +1039,11 @@ proc skip(L: var TLexer, tok: var TToken) = of '#': # do not skip documentation comment: if buf[pos+1] == '#': break - when defined(nimpretty): - tok.commentOffsetA = L.offsetBase + pos + when defined(nimpretty): hasComment = true if buf[pos+1] == '[': skipMultiLineComment(L, tok, pos+2, false) pos = L.bufpos buf = L.buf - when defined(nimpretty): - tok.commentOffsetB = L.offsetBase + pos else: tokenBegin(tok, pos) while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos) @@ -1053,6 +1055,9 @@ proc skip(L: var TLexer, tok: var TToken) = tokenEndPrevious(tok, pos-1) L.bufpos = pos when defined(nimpretty): + if hasComment: + tok.commentOffsetB = L.offsetBase + pos + tok.tokType = tkComment if gIndentationWidth <= 0: gIndentationWidth = tok.indent @@ -1074,6 +1079,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = else: tok.indent = -1 skip(L, tok) + when defined(nimpretty): + if tok.tokType == tkComment: return var c = L.buf[L.bufpos] tok.line = L.lineNumber tok.col = getColNumber(L, L.bufpos) From 9bc963508f29de8dd785a02b01f3159530a0ee2e Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 17 Apr 2018 11:09:23 +0200 Subject: [PATCH 015/214] nimpretty: next steps --- compiler/lexer.nim | 4 +++- compiler/msgs.nim | 18 ++++++++++++++++-- compiler/parser.nim | 8 +++++++- compiler/renderer.nim | 17 ++++++----------- tools/nimpretty.nim | 4 ++-- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 1d9279d02d..a4a2615bd9 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -1080,7 +1080,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = tok.indent = -1 skip(L, tok) when defined(nimpretty): - if tok.tokType == tkComment: return + if tok.tokType == tkComment: + L.indentAhead = L.currLineIndent + return var c = L.buf[L.bufpos] tok.line = L.lineNumber tok.col = getColNumber(L, L.bufpos) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 70504cfc94..818ab0c051 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -495,7 +495,9 @@ type # and parsed; usually 'nil' but is used # for 'nimsuggest' hash*: string # the checksum of the file - + when defined(nimpretty): + fullContent*: string + FileIndex* = int32 # XXX will make this 'distinct' later TLineInfo* = object # This is designed to be as small as possible, # because it is used # in syntax nodes. We save space here by using @@ -503,7 +505,7 @@ type # On 64 bit and on 32 bit systems this is # only 8 bytes. line*, col*: int16 - fileIndex*: int32 + fileIndex*: FileIndex when defined(nimpretty): offsetA*, offsetB*: int commentOffsetA*, commentOffsetB*: int @@ -583,6 +585,18 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo = result.quotedFullName = fullPath.makeCString if optEmbedOrigSrc in gGlobalOptions or true: result.lines = @[] + when defined(nimpretty): + if result.fullPath.len > 0: + try: + result.fullContent = readFile(result.fullPath) + except IOError: + #rawMessage(errCannotOpenFile, result.fullPath) + # XXX fixme + result.fullContent = "" + +when defined(nimpretty): + proc fileSection*(fid: FileIndex; a, b: int): string = + substr(fileInfos[fid].fullContent, a, b) proc fileInfoKnown*(filename: string): bool = var diff --git a/compiler/parser.nim b/compiler/parser.nim index 0019b7acb2..3bf75c6f74 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -125,7 +125,13 @@ proc rawSkipComment(p: var TParser, node: PNode) = if p.tok.tokType == tkComment: if node != nil: if node.comment == nil: node.comment = "" - add(node.comment, p.tok.literal) + when defined(nimpretty): + if p.tok.commentOffsetB > p.tok.commentOffsetA: + add node.comment, fileSection(p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB) + else: + add node.comment, p.tok.literal + else: + add(node.comment, p.tok.literal) else: parMessage(p, errInternal, "skipComment") getTok(p) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 7d513afb1c..0e631a8986 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -39,8 +39,7 @@ type inPragma: int when defined(nimpretty): pendingNewlineCount: int - origContent: string - + fid*: FileIndex # We render the source code in a two phases: The first # determines how long the subtree will likely be, the second @@ -354,13 +353,13 @@ proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string = proc atom(g: TSrcGen; n: PNode): string = when defined(nimpretty): let comment = if n.info.commentOffsetA < n.info.commentOffsetB: - " " & substr(g.origContent, n.info.commentOffsetA, n.info.commentOffsetB) + " " & fileSection(g.fid, n.info.commentOffsetA, n.info.commentOffsetB) else: "" if n.info.offsetA <= n.info.offsetB: # for some constructed tokens this can not be the case and we're better # off to not mess with the offset then. - return substr(g.origContent, n.info.offsetA, n.info.offsetB) & comment + return fileSection(g.fid, n.info.offsetA, n.info.offsetB) & comment var f: float32 case n.kind of nkEmpty: result = "" @@ -1460,17 +1459,13 @@ proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string = proc `$`*(n: PNode): string = n.renderTree proc renderModule*(n: PNode, infile, outfile: string, - renderFlags: TRenderFlags = {}) = + renderFlags: TRenderFlags = {}; + fid = FileIndex(-1)) = var f: File g: TSrcGen initSrcGen(g, renderFlags) - when defined(nimpretty): - try: - g.origContent = readFile(infile) - except IOError: - rawMessage(errCannotOpenFile, infile) - + g.fid = fid for i in countup(0, sonsLen(n) - 1): gsub(g, n.sons[i]) optNL(g) diff --git a/tools/nimpretty.nim b/tools/nimpretty.nim index 36d1382cff..396f17b0b8 100644 --- a/tools/nimpretty.nim +++ b/tools/nimpretty.nim @@ -24,7 +24,7 @@ const Usage: nimpretty [options] file.nim Options: - --backup:ON|OFF create a backup file before overwritting (default: ON) + --backup:on|off create a backup file before overwritting (default: ON) --version show the version --help show this help """ @@ -43,7 +43,7 @@ proc prettyPrint(infile: string) = let fileIdx = fileInfoIdx(infile) let tree = parseFile(fileIdx, newIdentCache()) let outfile = changeFileExt(infile, ".pretty.nim") - renderModule(tree, infile, outfile, {}) + renderModule(tree, infile, outfile, {}, fileIdx) proc main = var infile: string From 4a9f6f00adb3234e604faa40cca52bc15ede9769 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 18 Apr 2018 21:30:28 +0200 Subject: [PATCH 016/214] fixes system.doAssertRaises --- lib/system.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 9f0b115973..5e08dadc0b 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -4136,17 +4136,18 @@ template doAssertRaises*(exception, code: untyped): typed = runnableExamples: doAssertRaises(ValueError): raise newException(ValueError, "Hello World") - + var wrong = false try: - block: - code - raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code)) + code + wrong = true except exception: discard except Exception as exc: raiseAssert(astToStr(exception) & " wasn't raised, another error was raised instead by:\n"& astToStr(code)) + if wrong: + raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code)) when defined(cpp) and appType != "lib" and not defined(js) and not defined(nimscript) and hostOS != "standalone": From e237428d424ad18e03d4ffa6d036afb175d28bff Mon Sep 17 00:00:00 2001 From: WhiteDuke Date: Wed, 18 Apr 2018 23:29:10 +0200 Subject: [PATCH 017/214] Fix bright option (#7622) Setting the option to true, then to false would not turn off bright attribute. --- lib/pure/terminal.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 4f2f73ba75..002181a6f6 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -557,8 +557,8 @@ proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) = when defined(windows): let h = conHandle(f) var old = getAttributes(h) and not FOREGROUND_RGB - if bright: - old = old or FOREGROUND_INTENSITY + old = if bright: old or FOREGROUND_INTENSITY + else: old and not(FOREGROUND_INTENSITY) const lookup: array[ForegroundColor, int] = [ 0, (FOREGROUND_RED), @@ -579,8 +579,8 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) = when defined(windows): let h = conHandle(f) var old = getAttributes(h) and not BACKGROUND_RGB - if bright: - old = old or BACKGROUND_INTENSITY + old = if bright: old or BACKGROUND_INTENSITY + else: old and not(BACKGROUND_INTENSITY) const lookup: array[BackgroundColor, int] = [ 0, (BACKGROUND_RED), From 5d13e3f28bf479cd1d59fdec7f34847df988416c Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 19 Apr 2018 00:09:36 +0200 Subject: [PATCH 018/214] fixes #7507 --- lib/pure/strutils.nim | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index d772b066c2..54fdcb4d0b 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1647,11 +1647,15 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect, let last = s.high var i = 0 while true: - var j = find(a, s, sub, i, last) + let j = find(a, s, sub, i, last) if j < 0: break add result, substr(s, i, j - 1) add result, by - i = j + len(sub) + if sub.len == 0: + if i < s.len: add result, s[i] + i = j + 1 + else: + i = j + sub.len # copy the rest: add result, substr(s, i) @@ -1680,6 +1684,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, initSkipTable(a, sub) var i = 0 let last = s.high + let sublen = max(sub.len, 1) while true: var j = find(a, s, sub, i, last) if j < 0: break @@ -1688,7 +1693,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, (j+sub.len >= s.len or s[j+sub.len] notin wordChars): add result, substr(s, i, j - 1) add result, by - i = j + len(sub) + i = j + sublen else: add result, substr(s, i, j) i = j + 1 @@ -2546,6 +2551,9 @@ when isMainModule: doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" + doAssert "-lda-ldz -ld abc".replaceWord("") == "lda-ldz ld abc" + doAssert "oo".replace("", "abc") == "abcoabcoabc" + type MyEnum = enum enA, enB, enC, enuD, enE doAssert parseEnum[MyEnum]("enu_D") == enuD From 17cb2f2d4c23b2c7760b8a846dcc5884d5d40c89 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 18 Apr 2018 17:12:47 +0200 Subject: [PATCH 019/214] threadpool: minor documentation improvement --- lib/pure/concurrency/threadpool.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index a5eaec86ec..b01f8fc0da 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -245,7 +245,7 @@ proc `^`*[T](fv: FlowVar[T]): T = proc awaitAny*(flowVars: openArray[FlowVarBase]): int = ## awaits any of the given flowVars. Returns the index of one flowVar for ## which a value arrived. A flowVar only supports one call to 'awaitAny' at - ## the same time. That means if you await([a,b]) and await([b,c]) the second + ## the same time. That means if you awaitAny([a,b]) and awaitAny([b,c]) the second ## call will only await 'c'. If there is no flowVar left to be able to wait ## on, -1 is returned. ## **Note**: This results in non-deterministic behaviour and so should be From cb03ae2c9fcbb459b58bee90aa0759dcea6be878 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 18 Apr 2018 17:13:29 +0200 Subject: [PATCH 020/214] semstmts: fewer empty lines --- compiler/semstmts.nim | 5 ----- 1 file changed, 5 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f90e5c5f96..75d8cc2e0a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -779,20 +779,15 @@ proc semRaise(c: PContext, n: PNode): PNode = result = n checkSonsLen(n, 1) if n[0].kind != nkEmpty: - n[0] = semExprWithType(c, n[0]) let typ = n[0].typ - if not isImportedException(typ): - if typ.kind != tyRef or typ.lastSon.kind != tyObject: localError(n.info, errExprCannotBeRaised) - if not isException(typ.lastSon): localError(n.info, "raised object of type $1 does not inherit from Exception", [typeToString(typ)]) - proc addGenericParamListToScope(c: PContext, n: PNode) = if n.kind != nkGenericParams: illFormedAst(n) for i in countup(0, sonsLen(n)-1): From 0dc4d6dcc28a6e35f36caaa5bcc801b4acac61b4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 19 Apr 2018 08:54:16 +0200 Subject: [PATCH 021/214] fixes #7638; awaitAny blocks if the flow vars all have been complete already --- lib/pure/concurrency/threadpool.nim | 24 ++++++++++++++------ tests/parallel/twaitany.nim | 35 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 tests/parallel/twaitany.nim diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index b01f8fc0da..ca4f80f2a4 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -168,6 +168,15 @@ proc wakeupWorkerToProcessQueue(w: ptr Worker) = signal(w.q.empty) signal(w.taskArrived) +proc attach(fv: FlowVarBase; i: int): bool = + acquire(fv.cv.L) + if fv.cv.counter <= 0: + fv.idx = i + result = true + else: + result = false + release(fv.cv.L) + proc finished(fv: FlowVarBase) = doAssert fv.ai.isNil, "flowVar is still attached to an 'awaitAny'" # we have to protect against the rare cases where the owner of the flowVar @@ -248,23 +257,24 @@ proc awaitAny*(flowVars: openArray[FlowVarBase]): int = ## the same time. That means if you awaitAny([a,b]) and awaitAny([b,c]) the second ## call will only await 'c'. If there is no flowVar left to be able to wait ## on, -1 is returned. - ## **Note**: This results in non-deterministic behaviour and so should be - ## avoided. + ## **Note**: This results in non-deterministic behaviour and should be avoided. var ai: AwaitInfo ai.cv.initSemaphore() var conflicts = 0 + result = -1 for i in 0 .. flowVars.high: if cas(addr flowVars[i].ai, nil, addr ai): - flowVars[i].idx = i + if not attach(flowVars[i], i): + result = i + break else: inc conflicts if conflicts < flowVars.len: - await(ai.cv) - result = ai.idx + if result < 0: + await(ai.cv) + result = ai.idx for i in 0 .. flowVars.high: discard cas(addr flowVars[i].ai, addr ai, nil) - else: - result = -1 destroySemaphore(ai.cv) proc isReady*(fv: FlowVarBase): bool = diff --git a/tests/parallel/twaitany.nim b/tests/parallel/twaitany.nim new file mode 100644 index 0000000000..69136a3b65 --- /dev/null +++ b/tests/parallel/twaitany.nim @@ -0,0 +1,35 @@ +discard """ + output: '''true''' +""" + +# bug #7638 +import threadpool, os, strformat + +proc timer(d: int): int = + #echo fmt"sleeping {d}" + sleep(d) + #echo fmt"done {d}" + return d + +var durations = [1000, 2000, 3000, 4000, 5000] +var tasks: seq[FlowVarBase] = @[] +var results: seq[int] = @[] + +for i in 0 .. durations.high: + tasks.add spawn timer(durations[i]) + +var index = awaitAny(tasks) +while index != -1: + results.add ^cast[FlowVar[int]](tasks[index]) + tasks.del(index) + #echo repr results + index = awaitAny(tasks) + +doAssert results.len == 5 +doAssert 1000 in results +doAssert 2000 in results +doAssert 3000 in results +doAssert 4000 in results +doAssert 5000 in results +sync() +echo "true" From 34029263725ef931863ea73966dc08588758dada Mon Sep 17 00:00:00 2001 From: RSDuck Date: Thu, 19 Apr 2018 11:07:45 +0200 Subject: [PATCH 022/214] hasCustomPragma/getCustomPragmaVal: small fix (#7650) * fix hasCustomPragma/getCustomPragmaVal for types without pragma * fix pragma on pointer test * removed trailing spaces --- lib/core/macros.nim | 6 +++++- tests/pragmas/tcustom_pragma.nim | 10 +++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index b050eb6c88..1dc067e1ac 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1288,7 +1288,11 @@ proc customPragmaNode(n: NimNode): NimNode = typ = n.getTypeInst() if typ.typeKind == ntyTypeDesc: - return typ[1].getImpl()[0][1] + let impl = typ[1].getImpl() + if impl[0].kind == nnkPragmaExpr: + return impl[0][1] + else: + return impl[0] # handle types which don't have macro at all if n.kind == nnkSym: # either an variable or a proc let impl = n.getImpl() diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 28a8713ce6..33a4a7e65e 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -51,6 +51,9 @@ block: # A bit more advanced case static: assert(hasCustomPragma(myproc, alternativeKey)) + const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue) + static: assert(hasFieldCustomPragma == false) + # pragma on an object static: assert Subfield.hasCustomPragma(defaultValue) @@ -71,6 +74,8 @@ block: # ref types MyFile {.defaultValue: "closed".} = ref object path {.defaultValue: "invalid".}: string + TypeWithoutPragma = object + var s = NodeRef() const @@ -91,7 +96,7 @@ block: # ref types var ptrS = NodePtr(nil) const - ptrRightSerKey = getCustomPragmaVal(s.right, serializationKey) + ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey) static: assert ptrRightSerKey == "r" @@ -103,6 +108,9 @@ block: # ref types assert fileDefVal == "closed" assert filePathDefVal == "invalid" + static: + assert TypeWithoutPragma.hasCustomPragma(defaultValue) == false + block: type VariantKind = enum From 7e15d5134bb4c98a96307d16621eb836543bb083 Mon Sep 17 00:00:00 2001 From: jcosborn Date: Thu, 19 Apr 2018 15:39:18 -0500 Subject: [PATCH 023/214] allow setting template/macro recursive evaluation limits (#7652) * allow setting template/macro recursive evaluation limits * revert setting template/macro eval limits set them to 1000 --- compiler/commands.nim | 1 - compiler/evaltempl.nim | 5 +++-- compiler/hlo.nim | 2 +- compiler/msgs.nim | 6 ++++-- compiler/sem.nim | 2 +- compiler/vm.nim | 6 ++++-- doc/advopt.txt | 2 +- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 820cb7e1af..7274004a96 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -702,7 +702,6 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectNoArg(switch, arg, pass, info) useNimNamespace = true defineSymbol("cppCompileToNamespace") - else: if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) else: invalidCmdLineOption(pass, switch, info) diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 704ff819c9..fbb7eb2e6e 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -106,8 +106,9 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = for i in 1 .. genericParams: result.addSon n.sons[givenRegularParams + i] +# to prevent endless recursion in template instantiation +const evalTemplateLimit* = 1000 var evalTemplateCounter* = 0 - # to prevent endless recursion in templates instantiation proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = when true: @@ -133,7 +134,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = inc(evalTemplateCounter) - if evalTemplateCounter > 100: + if evalTemplateCounter > evalTemplateLimit: globalError(n.info, errTemplateInstantiationTooNested) result = n diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 2bffaa1730..c4288c3626 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -44,7 +44,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode = assert x.kind in {nkStmtList, nkCall} # better be safe than sorry, so check evalTemplateCounter too: inc(evalTemplateCounter) - if evalTemplateCounter > 100: + if evalTemplateCounter > evalTemplateLimit: globalError(n.info, errTemplateInstantiationTooNested) # deactivate this pattern: c.patterns[i] = nil diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 818ab0c051..749d29b556 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -87,7 +87,8 @@ type errNoReturnTypeDeclared, errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope, errXNeedsParamObjectType, - errTemplateInstantiationTooNested, errInstantiationFrom, + errTemplateInstantiationTooNested, errMacroInstantiationTooNested, + errInstantiationFrom, errInvalidIndexValueForTuple, errCommandExpectsFilename, errMainModuleMustBeSpecified, errXExpected, @@ -329,7 +330,8 @@ const errInvalidCommandX: "invalid command: \'$1\'", errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", - errTemplateInstantiationTooNested: "template/macro instantiation too nested", + errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N", + errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N", errInstantiationFrom: "template/generic instantiation from here", errInvalidIndexValueForTuple: "invalid index value for tuple subscript", errCommandExpectsFilename: "command expects a filename argument", diff --git a/compiler/sem.nim b/compiler/sem.nim index 4fef1bc604..041f2e1274 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -377,7 +377,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, ## reassigned, and binding the unbound identifiers that the macro output ## contains. inc(evalTemplateCounter) - if evalTemplateCounter > 100: + if evalTemplateCounter > evalTemplateLimit: globalError(s.info, errTemplateInstantiationTooNested) c.friendModules.add(s.owner.getModule) diff --git a/compiler/vm.nim b/compiler/vm.nim index 5ef782abde..5b5ccdce4e 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1729,14 +1729,16 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) = let posInCall = macroSym.typ.len + i yield (genericParam, call[posInCall]) +# to prevent endless recursion in macro instantiation +const evalMacroLimit = 1000 var evalMacroCounter: int proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, sym: PSym): PNode = # XXX globalError() is ugly here, but I don't know a better solution for now inc(evalMacroCounter) - if evalMacroCounter > 100: - globalError(n.info, errTemplateInstantiationTooNested) + if evalMacroCounter > evalMacroLimit: + globalError(n.info, errMacroInstantiationTooNested) # immediate macros can bypass any type and arity checking so we check the # arity here too: diff --git a/doc/advopt.txt b/doc/advopt.txt index 214ac8dd27..bf7dd7fb4f 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -76,7 +76,7 @@ Advanced options: --NimblePath:PATH add a path for Nimble support --noNimblePath deactivate the Nimble path --noCppExceptions use default exception handling with C++ backend - --cppCompileToNamespace use namespace "Nim" for the generated C++ code + --cppCompileToNamespace use namespace "Nim" for the generated C++ code --excludePath:PATH exclude a path from the list of search paths --dynlibOverride:SYMBOL marks SYMBOL so that dynlib:SYMBOL has no effect and can be statically linked instead; From 7d034d7b6a1e566c72c762c9e1576afa8d455410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Thu, 19 Apr 2018 22:41:06 +0200 Subject: [PATCH 024/214] Add `fromWinTime` and deprecate `unixTimeToWinTime`/`winTimeToUnixTime` (#7641) --- lib/pure/os.nim | 14 ++++++-------- lib/pure/times.nim | 39 ++++++++++++++++++++++++++------------- tests/stdlib/ttimes.nim | 9 ++++++++- 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 8298024d68..ddeee2c6b2 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -188,7 +188,7 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1".} var f: WIN32_FIND_DATA var h = findFirstFile(file, f) if h == -1'i32: raiseOSError(osLastError()) - result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftLastWriteTime)).int64) + result = fromWinTime(rdFileTime(f.ftLastWriteTime)) findClose(h) proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} = @@ -201,7 +201,7 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} = var f: WIN32_FIND_DATA var h = findFirstFile(file, f) if h == -1'i32: raiseOSError(osLastError()) - result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftLastAccessTime)).int64) + result = fromWinTime(rdFileTime(f.ftLastAccessTime)) findClose(h) proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} = @@ -218,7 +218,7 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} = var f: WIN32_FIND_DATA var h = findFirstFile(file, f) if h == -1'i32: raiseOSError(osLastError()) - result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftCreationTime)).int64) + result = fromWinTime(rdFileTime(f.ftCreationTime)) findClose(h) proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} = @@ -1512,16 +1512,14 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped = ## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows, ## or a 'Stat' structure on posix when defined(Windows): - template toTime(e: FILETIME): untyped {.gensym.} = - fromUnix(winTimeToUnixTime(rdFileTime(e)).int64) # local templates default to bind semantics template merge(a, b): untyped = a or (b shl 32) formalInfo.id.device = rawInfo.dwVolumeSerialNumber formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh) formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh) formalInfo.linkCount = rawInfo.nNumberOfLinks - formalInfo.lastAccessTime = toTime(rawInfo.ftLastAccessTime) - formalInfo.lastWriteTime = toTime(rawInfo.ftLastWriteTime) - formalInfo.creationTime = toTime(rawInfo.ftCreationTime) + formalInfo.lastAccessTime = fromWinTime(rdFileTime(rawInfo.ftLastAccessTime)) + formalInfo.lastWriteTime = fromWinTime(rdFileTime(rawInfo.ftLastWriteTime)) + formalInfo.creationTime = fromWinTime(rdFileTime(rawInfo.ftCreationTime)) # Retrieve basic permissions if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32: diff --git a/lib/pure/times.nim b/lib/pure/times.nim index cad32b51ac..bf63ed3442 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -374,9 +374,20 @@ proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} = ## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``). t.seconds +proc fromWinTime*(win: int64): Time = + ## Convert a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``) + ## to a ``Time``. + let hnsecsSinceEpoch = (win - epochDiff) + var seconds = hnsecsSinceEpoch div rateDiff + var nanos = ((hnsecsSinceEpoch mod rateDiff) * 100).int + if nanos < 0: + nanos += convert(Seconds, Nanoseconds, 1) + seconds -= 1 + result = initTime(seconds, nanos) + proc toWinTime*(t: Time): int64 = ## Convert ``t`` to a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``). - result = t.seconds * rateDiff + epochDiff + result = t.seconds * rateDiff + epochDiff + t.nanoseconds div 100 proc isLeapYear*(year: int): bool = ## Returns true if ``year`` is a leap year. @@ -860,10 +871,7 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} = elif defined(windows): var f: FILETIME getSystemTimeAsFileTime(f) - let nanosSinceEpoch = (rdFileTime(f) - epochDiff) * 100 - let seconds = convert(Nanoseconds, Seconds, nanosSinceEpoch) - let nanos = (nanosSinceEpoch mod convert(Seconds, Nanoseconds, 1)).int - result = initTime(seconds, nanos) + result = fromWinTime(rdFileTime(f)) proc now*(): DateTime {.tags: [TimeEffect], benign.} = ## Get the current time as a ``DateTime`` in the local timezone. @@ -1720,14 +1728,6 @@ when not defined(JS): var clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int - proc unixTimeToWinTime*(time: CTime): int64 = - ## converts a UNIX `Time` (``time_t``) to a Windows file time - result = int64(time) * rateDiff + epochDiff - - proc winTimeToUnixTime*(time: int64): CTime = - ## converts a Windows time to a UNIX `Time` (``time_t``) - result = CTime((time - epochDiff) div rateDiff) - when not defined(useNimRtl): proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} = ## gets time spent that the CPU spent to run the current process in @@ -1769,6 +1769,19 @@ when defined(JS): # Deprecated procs +when not defined(JS): + proc unixTimeToWinTime*(time: CTime): int64 {.deprecated: "Use toWinTime instead".} = + ## Converts a UNIX `Time` (``time_t``) to a Windows file time + ## + ## **Deprecated:** use ``toWinTime`` instead. + result = int64(time) * rateDiff + epochDiff + + proc winTimeToUnixTime*(time: int64): CTime {.deprecated: "Use fromWinTime instead".} = + ## Converts a Windows time to a UNIX `Time` (``time_t``) + ## + ## **Deprecated:** use ``fromWinTime`` instead. + result = CTime((time - epochDiff) div rateDiff) + proc initInterval*(seconds, minutes, hours, days, months, years: int = 0): TimeInterval {.deprecated.} = ## **Deprecated since v0.18.0:** use ``initTimeInterval`` instead. diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index f359652865..945d7ba3dc 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -409,4 +409,11 @@ suite "ttimes": # Bug with adding a day to a Time let day = 24.hours let tomorrow = now + day - check tomorrow - now == initDuration(days = 1) \ No newline at end of file + check tomorrow - now == initDuration(days = 1) + + test "fromWinTime/toWinTime": + check 0.fromUnix.toWinTime.fromWinTime.toUnix == 0 + check (-1).fromWinTime.nanoseconds == convert(Seconds, Nanoseconds, 1) - 100 + check -1.fromWinTime.toWinTime == -1 + # One nanosecond is discarded due to differences in time resolution + check initTime(0, 101).toWinTime.fromWinTime.nanoseconds == 100 \ No newline at end of file From 262aafa0a915fc5c769824f7f7d63f9dc9e649c7 Mon Sep 17 00:00:00 2001 From: tersec Date: Fri, 20 Apr 2018 05:04:50 +0000 Subject: [PATCH 025/214] https://reproducible-builds.org/ support via SOURCE_DATE_EPOCH (#7644) (#7661) --- compiler/semfold.nim | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 096fc19e07..6fcc9a0a4b 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -483,6 +483,19 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode = proc getConstExpr(m: PSym, n: PNode): PNode = result = nil + + proc getSrcTimestamp(): DateTime = + try: + result = utc(fromUnix(parseInt(getEnv("SOURCE_DATE_EPOCH", + "not a number")))) + except ValueError: + # Environment variable malformed. + # https://reproducible-builds.org/specs/source-date-epoch/: "If the + # value is malformed, the build process SHOULD exit with a non-zero + # error code", which this doesn't do. This uses local time, because + # that maintains compatibility with existing usage. + result = local(getTime()) + case n.kind of nkSym: var s = n.sym @@ -492,8 +505,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of skConst: case s.magic of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n) - of mCompileDate: result = newStrNodeT(times.getDateStr(), n) - of mCompileTime: result = newStrNodeT(times.getClockStr(), n) + of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(), + "yyyy-MM-dd"), n) + of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(), + "HH:mm:ss"), n) of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n) of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n) of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n) From 9cc8fec370867d2f75b16c3ec85a38a5c379909a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 20 Apr 2018 08:45:03 +0200 Subject: [PATCH 026/214] replace --advanced by --fullhelp; refs #7621 --- compiler/commands.nim | 11 +++++++++++ doc/basicopt.txt | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 7274004a96..ec58706f36 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -77,6 +77,14 @@ proc writeAdvancedUsage(pass: TCmdLinePass) = {msgStdout}) msgQuit(0) +proc writeFullhelp(pass: TCmdLinePass) = + if pass == passCmd1: + msgWriteln(`%`(HelpMessage, [VersionAsString, + platform.OS[platform.hostOS].name, + CPU[platform.hostCPU].name]) & Usage & AdvancedUsage, + {msgStdout}) + msgQuit(0) + proc writeVersionInfo(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(`%`(HelpMessage, [VersionAsString, @@ -611,6 +619,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "advanced": expectNoArg(switch, arg, pass, info) writeAdvancedUsage(pass) + of "fullhelp": + expectNoArg(switch, arg, pass, info) + writeFullhelp(pass) of "help", "h": expectNoArg(switch, arg, pass, info) helpOnError(pass) diff --git a/doc/basicopt.txt b/doc/basicopt.txt index 4db2d5af74..4c11cc767e 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -36,7 +36,7 @@ Options: --app:console|gui|lib|staticlib generate a console app|GUI app|DLL|static library -r, --run run the compiled program with given arguments - --advanced show advanced command line switches + --fullhelp show all command line switches -h, --help show this help Note, single letter options that take an argument require a colon. E.g. -p:PATH. From 6667362c2f1cd0fc1fdb1dacb486528b928470d5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 20 Apr 2018 08:54:56 +0200 Subject: [PATCH 027/214] refs #7586; show surounding source also for hints and warnsings --- compiler/msgs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 749d29b556..35be5e7727 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -1048,7 +1048,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, KindColor, `%`(KindFormat, kind)) else: styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s) - if msg in errMin..errMax and hintSource in gNotes: + if hintSource in gNotes: info.writeSurroundingSrc handleError(msg, eh, s) From 33b69f0ed0272a4792322d9a0fbaffd5bef2f6e9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 21 Apr 2018 08:13:37 +0200 Subject: [PATCH 028/214] refactoring: make FileIndex a distinct type; make line information an uint16; fixes #7654 --- compiler/ast.nim | 10 +-- compiler/ccgexprs.nim | 2 +- compiler/cgen.nim | 12 ++-- compiler/commands.nim | 2 +- compiler/docgen.nim | 10 +-- compiler/filter_tmpl.nim | 6 +- compiler/jsgen.nim | 2 +- compiler/lexer.nim | 18 +++--- compiler/main.nim | 4 +- compiler/modulegraphs.nim | 40 ++++++------ compiler/modulepaths.nim | 2 +- compiler/modules.nim | 20 +++--- compiler/msgs.nim | 107 ++++++++++++++++--------------- compiler/nimfix/pretty.nim | 10 +-- compiler/nimfix/prettybase.nim | 16 ++--- compiler/parampatterns.nim | 3 +- compiler/parser.nim | 2 +- compiler/passes.nim | 24 ++----- compiler/pbraces.nim | 2 +- compiler/pragmas.nim | 2 +- compiler/reorder.nim | 20 +++--- compiler/rod.nim | 112 +-------------------------------- compiler/rodread.nim | 47 +++++++------- compiler/rodwrite.nim | 10 +-- compiler/semdata.nim | 2 +- compiler/semstmts.nim | 8 +-- compiler/suggest.nim | 4 +- compiler/syntaxes.nim | 4 +- compiler/vm.nim | 6 +- 29 files changed, 196 insertions(+), 311 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index da7e828f28..4a0a9a20bf 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1042,9 +1042,9 @@ proc newNode*(kind: TNodeKind): PNode = new(result) result.kind = kind #result.info = UnknownLineInfo() inlined: - result.info.fileIndex = int32(-1) + result.info.fileIndex = InvalidFileIdx result.info.col = int16(-1) - result.info.line = int16(-1) + result.info.line = uint16(0) when defined(useNodeIds): result.id = gNodeId if result.id == nodeIdToDebug: @@ -1116,13 +1116,13 @@ proc linkTo*(s: PSym, t: PType): PSym {.discardable.} = s.typ = t result = s -template fileIdx*(c: PSym): int32 = +template fileIdx*(c: PSym): FileIndex = # XXX: this should be used only on module symbols - c.position.int32 + c.position.FileIndex template filename*(c: PSym): string = # XXX: this should be used only on module symbols - c.position.int32.toFilename + c.position.FileIndex.toFilename proc appendToModule*(m: PSym, n: PNode) = ## The compiler will use this internally to add nodes that will be diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 7e3c2632a8..461a862986 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2023,7 +2023,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} = let theMacro = it[0].sym add p.s(cpsStmts), initFrameNoDebug(p, frameName, makeCString theMacro.name.s, - theMacro.info.quotedFilename, it.info.line) + theMacro.info.quotedFilename, it.info.line.int) else: genStmts(p, it) if n.len > 0: exprOrStmt diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 4d3cabd3a6..9e1f9349ff 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -223,7 +223,7 @@ proc genLineDir(p: BProc, t: PNode) = line.rope, makeCString(toFilename(tt.info))) elif ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and - (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex >= 0: + (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX: if freshLineInfo(p, tt.info): linefmt(p, cpsStmts, "nimln_($1, $2);$n", line.rope, tt.info.quotedFilename) @@ -678,7 +678,7 @@ proc generateHeaders(m: BModule) = proc openNamespaceNim(): Rope = result.add("namespace Nim {" & tnl) - + proc closeNamespaceNim(): Rope = result.add("}" & tnl) @@ -1090,7 +1090,7 @@ proc genMainProc(m: BModule) = appcg(m, m.s[cfsProcs], nimMain, [m.g.mainModInit, initStackBottomCall, rope(m.labels)]) if optNoMain notin gGlobalOptions: - if useNimNamespace: + if useNimNamespace: m.s[cfsProcs].add closeNamespaceNim() & "using namespace Nim;" & tnl appcg(m, m.s[cfsProcs], otherMain, []) @@ -1202,7 +1202,7 @@ proc genModule(m: BModule, cfile: Cfile): Rope = add(result, genSectionStart(i)) add(result, m.s[i]) add(result, genSectionEnd(i)) - if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim() + if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim() add(result, m.s[cfsInitProc]) if useNimNamespace: result.add closeNamespaceNim() @@ -1301,7 +1301,7 @@ proc resetCgenModules*(g: BModuleList) = for m in cgenModules(g): resetModule(m) proc rawNewModule(g: BModuleList; module: PSym): BModule = - result = rawNewModule(g, module, module.position.int32.toFullPath) + result = rawNewModule(g, module, module.position.FileIndex.toFullPath) proc newModule(g: BModuleList; module: PSym): BModule = # we should create only one cgen module for each module sym @@ -1311,7 +1311,7 @@ proc newModule(g: BModuleList; module: PSym): BModule = if (optDeadCodeElim in gGlobalOptions): if (sfDeadCodeElim in module.flags): - internalError("added pending module twice: " & module.filename) + internalError("added pending module twice: " & toFilename(FileIndex module.position)) template injectG(config) {.dirty.} = if graph.backend == nil: diff --git a/compiler/commands.nim b/compiler/commands.nim index ec58706f36..e1dc1aacf3 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -319,7 +319,7 @@ proc trackDirty(arg: string, info: TLineInfo) = localError(info, errInvalidNumber, a[2]) let dirtyOriginalIdx = a[1].fileInfoIdx - if dirtyOriginalIdx >= 0: + if dirtyOriginalIdx.int32 >= 0: msgs.setDirtyFile(dirtyOriginalIdx, a[0]) gTrackPos = newLineInfo(dirtyOriginalIdx, line, column) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 74fb305ac6..6f3dcde8b8 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -544,7 +544,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments}) - result = %{ "name": %name, "type": %($k), "line": %n.info.line, + result = %{ "name": %name, "type": %($k), "line": %n.info.line.int, "col": %n.info.col} if comm != nil and comm != "": result["description"] = %comm @@ -618,7 +618,7 @@ proc generateJson*(d: PDoc, n: PNode) = of nkCommentStmt: if n.comment != nil and startsWith(n.comment, "##"): let stripped = n.comment.substr(2).strip - d.add %{ "comment": %stripped, "line": %n.info.line, + d.add %{ "comment": %stripped, "line": %n.info.line.int, "col": %n.info.col } of nkProcDef: when useEffectSystem: documentRaises(n) @@ -790,7 +790,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string, discard "fixme: error report" proc commandDoc*() = - var ast = parseFile(gProjectMainIdx, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true @@ -840,7 +840,7 @@ proc commandRst2TeX*() = commandRstAux(gProjectFull, TexExt) proc commandJson*() = - var ast = parseFile(gProjectMainIdx, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true @@ -855,7 +855,7 @@ proc commandJson*() = writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false) proc commandTags*() = - var ast = parseFile(gProjectMainIdx, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index ca9a3a801c..a1ba9113c1 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -35,7 +35,7 @@ const proc newLine(p: var TTmplParser) = llStreamWrite(p.outp, repeat(')', p.emitPar)) p.emitPar = 0 - if p.info.line > int16(1): llStreamWrite(p.outp, "\n") + if p.info.line > uint16(1): llStreamWrite(p.outp, "\n") if p.pendingExprLine: llStreamWrite(p.outp, spaces(2)) p.pendingExprLine = false @@ -212,9 +212,9 @@ proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream = p.x = newStringOfCap(120) # do not process the first line which contains the directive: if llStreamReadLine(p.inp, p.x): - p.info.line = p.info.line + int16(1) + p.info.line = p.info.line + 1'u16 while llStreamReadLine(p.inp, p.x): - p.info.line = p.info.line + int16(1) + p.info.line = p.info.line + 1'u16 parseLine(p) newLine(p) result = p.outp diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 4755089463..2ae3426ab4 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2261,7 +2261,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = var m = BModule(b) if sfMainModule in m.module.flags: let ext = "js" - let f = if globals.classes.len == 0: m.module.filename + let f = if globals.classes.len == 0: toFilename(FileIndex m.module.position) else: "nimsystem" let code = wholeCode(graph, m) let outfile = diff --git a/compiler/lexer.nim b/compiler/lexer.nim index a4a2615bd9..0b1090bb1f 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -133,7 +133,7 @@ type TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string) TLexer* = object of TBaseLexer - fileIdx*: int32 + fileIdx*: FileIndex indentAhead*: int # if > 0 an indendation has already been read # this is needed because scanning comments # needs so much look-ahead @@ -222,7 +222,7 @@ proc fillToken(L: var TToken) = L.commentOffsetA = 0 L.commentOffsetB = 0 -proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream; +proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache) = openBaseLexer(lex, inputstream) lex.fileIdx = fileidx @@ -274,7 +274,7 @@ template tokenEnd(tok, pos) {.dirty.} = when defined(nimsuggest): let colB = getColNumber(L, pos)+1 if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and - L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}: + L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}: L.cursor = CursorPosition.InToken gTrackPos.col = colA.int16 colA = 0 @@ -285,9 +285,9 @@ template tokenEndIgnore(tok, pos) = when defined(nimsuggest): let colB = getColNumber(L, pos) if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and - L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}: + L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}: gTrackPos.fileIndex = trackPosInvalidFileIdx - gTrackPos.line = -1 + gTrackPos.line = 0'u16 colA = 0 when defined(nimpretty): tok.offsetB = L.offsetBase + pos @@ -299,7 +299,7 @@ template tokenEndPrevious(tok, pos) = # the cursor in a string literal or comment: let colB = getColNumber(L, pos) if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and - L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}: + L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}: L.cursor = CursorPosition.BeforeToken gTrackPos = L.previousToken gTrackPosAttached = true @@ -1066,7 +1066,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = when defined(nimsuggest): # we attach the cursor to the last *strong* token if tok.tokType notin weakTokens: - L.previousToken.line = tok.line.int16 + L.previousToken.line = tok.line.uint16 L.previousToken.col = tok.col.int16 when defined(nimsuggest): @@ -1118,7 +1118,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = tok.tokType = tkParLe when defined(nimsuggest): if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and - tok.line == gTrackPos.line and gIdeCmd == ideCon: + tok.line == gTrackPos.line.int and gIdeCmd == ideCon: gTrackPos.col = tok.col.int16 of ')': tok.tokType = tkParRi @@ -1139,7 +1139,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = of '.': when defined(nimsuggest): if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and - tok.line == gTrackPos.line and gIdeCmd == ideSug: + tok.line == gTrackPos.line.int and gIdeCmd == ideSug: tok.tokType = tkDot L.cursor = CursorPosition.InToken gTrackPos.col = tok.col.int16 diff --git a/compiler/main.nim b/compiler/main.nim index c928c81cd0..401099fc38 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -35,7 +35,7 @@ proc writeDepsFile(g: ModuleGraph; project: string) = let f = open(changeFileExt(project, "deps"), fmWrite) for m in g.modules: if m != nil: - f.writeLine(toFullPath(m.position.int32)) + f.writeLine(toFullPath(m.position.FileIndex)) for k in g.inclToMod.keys: if g.getModule(k).isNil: # don't repeat includes which are also modules f.writeLine(k.toFullPath) @@ -265,7 +265,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = of "parse": gCmd = cmdParse wantMainModule() - discard parseFile(gProjectMainIdx, cache) + discard parseFile(FileIndex gProjectMainIdx, cache) of "scan": gCmd = cmdScan wantMainModule() diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 2c59a9097d..6c14a46e82 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -25,7 +25,7 @@ ## - Its dependent module stays the same. ## -import ast, intsets, tables, options, rod +import ast, intsets, tables, options, rod, msgs, hashes type ModuleGraph* = ref object @@ -34,10 +34,10 @@ type deps*: IntSet # the dependency graph or potentially its transitive closure. suggestMode*: bool # whether we are in nimsuggest mode or not. invalidTransitiveClosure: bool - inclToMod*: Table[int32, int32] # mapping of include file to the - # first module that included it - importStack*: seq[int32] # The current import stack. Used for detecting recursive - # module dependencies. + inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the + # first module that included it + importStack*: seq[FileIndex] # The current import stack. Used for detecting recursive + # module dependencies. backend*: RootRef # minor hack so that a backend can extend this easily config*: ConfigRef doStopCompile*: proc(): bool {.closure.} @@ -45,6 +45,8 @@ type owners*: seq[PSym] methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]] +proc hash*(x: FileIndex): Hash {.borrow.} + {.this: g.} proc stopCompile*(g: ModuleGraph): bool {.inline.} = @@ -56,7 +58,7 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = result.deps = initIntSet() result.modules = @[] result.importStack = @[] - result.inclToMod = initTable[int32, int32]() + result.inclToMod = initTable[FileIndex, FileIndex]() if config.isNil: result.config = newConfigRef() else: @@ -69,35 +71,35 @@ proc resetAllModules*(g: ModuleGraph) = deps = initIntSet() modules = @[] importStack = @[] - inclToMod = initTable[int32, int32]() + inclToMod = initTable[FileIndex, FileIndex]() usageSym = nil owners = @[] methods = @[] -proc getModule*(g: ModuleGraph; fileIdx: int32): PSym = - if fileIdx >= 0 and fileIdx < modules.len: - result = modules[fileIdx] +proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = + if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len: + result = modules[fileIdx.int32] proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b -proc addDep*(g: ModuleGraph; m: PSym, dep: int32) = - assert m.position == m.info.fileIndex +proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) = + assert m.position == m.info.fileIndex.int32 addModuleDep(m.info.fileIndex, dep, isIncludeFile = false) if suggestMode: - deps.incl m.position.dependsOn(dep) + deps.incl m.position.dependsOn(dep.int) # we compute the transitive closure later when quering the graph lazily. # this improve efficiency quite a lot: #invalidTransitiveClosure = true -proc addIncludeDep*(g: ModuleGraph; module, includeFile: int32) = +proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) = addModuleDep(module, includeFile, isIncludeFile = true) discard hasKeyOrPut(inclToMod, includeFile, module) -proc parentModule*(g: ModuleGraph; fileIdx: int32): int32 = +proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex = ## returns 'fileIdx' if the file belonging to this index is ## directly used as a module or else the module that first ## references this include file. - if fileIdx >= 0 and fileIdx < modules.len and modules[fileIdx] != nil: + if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len and modules[fileIdx.int32] != nil: result = fileIdx else: result = inclToMod.getOrDefault(fileIdx) @@ -111,11 +113,11 @@ proc transitiveClosure(g: var IntSet; n: int) = if g.contains(i.dependsOn(k)) and g.contains(k.dependsOn(j)): g.incl i.dependsOn(j) -proc markDirty*(g: ModuleGraph; fileIdx: int32) = +proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) = let m = getModule fileIdx if m != nil: incl m.flags, sfDirty -proc markClientsDirty*(g: ModuleGraph; fileIdx: int32) = +proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) = # we need to mark its dependent modules D as dirty right away because after # nimsuggest is done with this module, the module's dirty flag will be # cleared but D still needs to be remembered as 'dirty'. @@ -126,7 +128,7 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: int32) = # every module that *depends* on this file is also dirty: for i in 0i32..=% L: result = unknownLineInfo() else: result = msgContext[i] -template toFilename*(fileIdx: int32): string = - (if fileIdx < 0: "???" else: fileInfos[fileIdx].projPath) +template toFilename*(fileIdx: FileIndex): string = + (if fileIdx.int32 < 0: "???" else: fileInfos[fileIdx.int32].projPath) -proc toFullPath*(fileIdx: int32): string = - if fileIdx < 0: result = "???" - else: result = fileInfos[fileIdx].fullPath +proc toFullPath*(fileIdx: FileIndex): string = + if fileIdx.int32 < 0: result = "???" + else: result = fileInfos[fileIdx.int32].fullPath -proc setDirtyFile*(fileIdx: int32; filename: string) = - assert fileIdx >= 0 - fileInfos[fileIdx].dirtyFile = filename +proc setDirtyFile*(fileIdx: FileIndex; filename: string) = + assert fileIdx.int32 >= 0 + fileInfos[fileIdx.int32].dirtyFile = filename -proc setHash*(fileIdx: int32; hash: string) = - assert fileIdx >= 0 - shallowCopy(fileInfos[fileIdx].hash, hash) +proc setHash*(fileIdx: FileIndex; hash: string) = + assert fileIdx.int32 >= 0 + shallowCopy(fileInfos[fileIdx.int32].hash, hash) -proc getHash*(fileIdx: int32): string = - assert fileIdx >= 0 - shallowCopy(result, fileInfos[fileIdx].hash) +proc getHash*(fileIdx: FileIndex): string = + assert fileIdx.int32 >= 0 + shallowCopy(result, fileInfos[fileIdx.int32].hash) -proc toFullPathConsiderDirty*(fileIdx: int32): string = - if fileIdx < 0: +proc toFullPathConsiderDirty*(fileIdx: FileIndex): string = + if fileIdx.int32 < 0: result = "???" - elif not fileInfos[fileIdx].dirtyFile.isNil: - result = fileInfos[fileIdx].dirtyFile + elif not fileInfos[fileIdx.int32].dirtyFile.isNil: + result = fileInfos[fileIdx.int32].dirtyFile else: - result = fileInfos[fileIdx].fullPath + result = fileInfos[fileIdx.int32].fullPath template toFilename*(info: TLineInfo): string = info.fileIndex.toFilename @@ -762,15 +765,15 @@ template toFullPath*(info: TLineInfo): string = info.fileIndex.toFullPath proc toMsgFilename*(info: TLineInfo): string = - if info.fileIndex < 0: + if info.fileIndex.int32 < 0: result = "???" elif gListFullPaths: - result = fileInfos[info.fileIndex].fullPath + result = fileInfos[info.fileIndex.int32].fullPath else: - result = fileInfos[info.fileIndex].projPath + result = fileInfos[info.fileIndex.int32].projPath proc toLinenumber*(info: TLineInfo): int {.inline.} = - result = info.line + result = int info.line proc toColumn*(info: TLineInfo): int {.inline.} = result = info.col @@ -787,7 +790,7 @@ proc `??`* (info: TLineInfo, filename: string): bool = # only for debugging purposes result = filename in info.toFilename -const trackPosInvalidFileIdx* = -2 # special marker so that no suggestions +const trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions # are produced within comments and string literals var gTrackPos*: TLineInfo var gTrackPosAttached*: bool ## whether the tracking position was attached to some @@ -926,7 +929,7 @@ proc writeContext(lastinfo: TLineInfo) = else: styledMsgWriteln(styleBright, PosFormat % [toMsgFilename(msgContext[i]), - coordToStr(msgContext[i].line), + coordToStr(msgContext[i].line.int), coordToStr(msgContext[i].col+1)], resetStyle, getMessageStr(errInstantiationFrom, "")) @@ -994,7 +997,7 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string = of warnMin..warnMax: WarningTitle of hintMin..hintMax: HintTitle else: ErrorTitle - result = PosFormat % [toMsgFilename(info), coordToStr(info.line), + result = PosFormat % [toMsgFilename(info), coordToStr(info.line.int), coordToStr(info.col+1)] & title & getMessageStr(msg, arg) @@ -1035,7 +1038,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, # NOTE: currently line info line numbers start with 1, # but column numbers start with 0, however most editors expect # first column to be 1, so we need to +1 here - let x = PosFormat % [toMsgFilename(info), coordToStr(info.line), + let x = PosFormat % [toMsgFilename(info), coordToStr(info.line.int), coordToStr(info.col+1)] let s = getMessageStr(msg, arg) @@ -1093,30 +1096,30 @@ template assertNotNil*(e): untyped = template internalAssert*(e: bool) = if not e: internalError($instantiationInfo()) -proc addSourceLine*(fileIdx: int32, line: string) = - fileInfos[fileIdx].lines.add line.rope +proc addSourceLine*(fileIdx: FileIndex, line: string) = + fileInfos[fileIdx.int32].lines.add line.rope proc sourceLine*(i: TLineInfo): Rope = - if i.fileIndex < 0: return nil + if i.fileIndex.int32 < 0: return nil - if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0: + if not optPreserveOrigSource and fileInfos[i.fileIndex.int32].lines.len == 0: try: for line in lines(i.toFullPath): addSourceLine i.fileIndex, line.string except IOError: discard - internalAssert i.fileIndex < fileInfos.len + internalAssert i.fileIndex.int32 < fileInfos.len # can happen if the error points to EOF: - if i.line > fileInfos[i.fileIndex].lines.len: return nil + if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil - result = fileInfos[i.fileIndex].lines[i.line-1] + result = fileInfos[i.fileIndex.int32].lines[i.line.int-1] proc quotedFilename*(i: TLineInfo): Rope = - internalAssert i.fileIndex >= 0 + internalAssert i.fileIndex.int32 >= 0 if optExcessiveStackTrace in gGlobalOptions: - result = fileInfos[i.fileIndex].quotedFullName + result = fileInfos[i.fileIndex.int32].quotedFullName else: - result = fileInfos[i.fileIndex].quotedName + result = fileInfos[i.fileIndex.int32].quotedName ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) = case err diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim index 55603f4cd7..4627264dc4 100644 --- a/compiler/nimfix/pretty.nim +++ b/compiler/nimfix/pretty.nim @@ -28,7 +28,7 @@ proc overwriteFiles*() = let doStrip = options.getConfigVar("pretty.strip").normalize == "on" for i in 0 .. high(gSourceFiles): if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and - (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx): + (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex): let newFile = if gOverWrite: gSourceFiles[i].fullpath else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim") try: @@ -95,7 +95,7 @@ proc beautifyName(s: string, k: TSymKind): string = proc replaceInFile(info: TLineInfo; newName: string) = loadFile(info) - let line = gSourceFiles[info.fileIndex].lines[info.line-1] + let line = gSourceFiles[info.fileIndex.int].lines[info.line.int-1] var first = min(info.col.int, line.len) if first < 0: return #inc first, skipIgnoreCase(line, "proc ", first) @@ -107,8 +107,8 @@ proc replaceInFile(info: TLineInfo; newName: string) = if differ(line, first, last, newName): # last-first+1 != newName.len or var x = line.substr(0, first-1) & newName & line.substr(last+1) - system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x) - gSourceFiles[info.fileIndex].dirty = true + system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x) + gSourceFiles[info.fileIndex.int].dirty = true proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) = let beau = beautifyName(s, k) @@ -136,7 +136,7 @@ template styleCheckDef*(s: PSym) = styleCheckDef(s.info, s, s.kind) proc styleCheckUseImpl(info: TLineInfo; s: PSym) = - if info.fileIndex < 0: return + if info.fileIndex.int < 0: return # we simply convert it to what it looks like in the definition # for consistency diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim index f1d24183b0..ecb4b00931 100644 --- a/compiler/nimfix/prettybase.nim +++ b/compiler/nimfix/prettybase.nim @@ -16,13 +16,13 @@ type lines*: seq[string] dirty*, isNimfixFile*: bool fullpath*, newline*: string - fileIdx*: int32 + fileIdx*: FileIndex var gSourceFiles*: seq[TSourceFile] = @[] proc loadFile*(info: TLineInfo) = - let i = info.fileIndex + let i = info.fileIndex.int if i >= gSourceFiles.len: gSourceFiles.setLen(i+1) if gSourceFiles[i].lines.isNil: @@ -64,7 +64,7 @@ proc differ*(line: string, a, b: int, x: string): bool = proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) = loadFile(info) - let line = gSourceFiles[info.fileIndex].lines[info.line-1] + let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1] var first = min(info.col.int, line.len) if first < 0: return #inc first, skipIgnoreCase(line, "proc ", first) @@ -75,8 +75,8 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) = let last = first+identLen(line, first)-1 if cmpIgnoreStyle(line[first..last], oldSym.s) == 0: var x = line.substr(0, first-1) & newSym.s & line.substr(last+1) - system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x) - gSourceFiles[info.fileIndex].dirty = true + system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x) + gSourceFiles[info.fileIndex.int32].dirty = true #if newSym.s == "File": writeStackTrace() proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) = @@ -85,10 +85,10 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) = proc replaceComment*(info: TLineInfo) = loadFile(info) - let line = gSourceFiles[info.fileIndex].lines[info.line-1] + let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1] var first = info.col.int if line[first] != '#': inc first var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape - system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x) - gSourceFiles[info.fileIndex].dirty = true + system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x) + gSourceFiles[info.fileIndex.int32].dirty = true diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 8540f1b320..02c48c16d2 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -235,7 +235,8 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult result = arLValue else: result = isAssignable(owner, n.sons[0], isUnsafeAddr) - if result != arNone and sfDiscriminant in n.sons[1].sym.flags: + if result != arNone and n[1].kind == nkSym and + sfDiscriminant in n[1].sym.flags: result = arDiscriminant of nkBracketExpr: if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in diff --git a/compiler/parser.nim b/compiler/parser.nim index 3bf75c6f74..ac0a577708 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -83,7 +83,7 @@ proc getTok(p: var TParser) = rawGetTok(p.lex, p.tok) p.hasProgress = true -proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream, +proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, cache: IdentCache; strongSpaces=false) = ## Open a parser, using the given arguments to set up its internal state. diff --git a/compiler/passes.nim b/compiler/passes.nim index f079100eaa..d7c1816768 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -52,8 +52,8 @@ proc makePass*(open: TPassOpen = nil, # the semantic checker needs these: var - gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.} - gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.} + gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PSym {.nimcall.} + gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.nimcall.} # implementation @@ -63,20 +63,6 @@ proc skipCodegen*(n: PNode): bool {.inline.} = # error count instead. result = msgs.gErrorCounter > 0 -proc astNeeded*(s: PSym): bool = - # The ``rodwrite`` module uses this to determine if the body of a proc - # needs to be stored. The passes manager frees s.sons[codePos] when - # appropriate to free the procedure body's memory. This is important - # to keep memory usage down. - if (s.kind in {skMethod, skProc, skFunc}) and - ({sfCompilerProc, sfCompileTime} * s.flags == {}) and - (s.typ.callConv != ccInline) and - (s.ast.sons[genericParamsPos].kind == nkEmpty): - result = false - # XXX this doesn't really make sense with excessive CTFE - else: - result = true - const maxPasses = 10 @@ -153,7 +139,7 @@ proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) = m = gPasses[i].close(graph, a[i], m) a[i] = nil # free the memory here -proc resolveMod(module, relativeTo: string): int32 = +proc resolveMod(module, relativeTo: string): FileIndex = let fullPath = findModule(module, relativeTo) if fullPath.len == 0: result = InvalidFileIDX @@ -166,7 +152,7 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind, let relativeTo = m.info.toFullPath for module in items(implicits): # implicit imports should not lead to a module importing itself - if m.position != resolveMod(module, relativeTo): + if m.position != resolveMod(module, relativeTo).int32: var importStmt = newNodeI(nodeKind, gCmdLineInfo) var str = newStrNode(nkStrLit, module) str.info = gCmdLineInfo @@ -180,7 +166,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, p: TParsers a: TPassContextArray s: PLLStream - fileIdx = module.fileIdx + fileIdx = FileIndex module.fileIdx if module.id < 0: # new module caching mechanism: for i in 0..= gMods.len: setLen(gMods, fileIdx+1) - gMods[fileIdx].hash = result + if fileIdx.int32 >= gMods.len: setLen(gMods, fileIdx.int32+1) + gMods[fileIdx.int32].hash = result template growCache*(cache, pos) = if cache.len <= pos: cache.setLen(pos+1) -proc checkDep(fileIdx: int32; cache: IdentCache): TReasonForRecompile = +proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile = assert fileIdx != InvalidFileIDX - growCache gMods, fileIdx - if gMods[fileIdx].reason != rrEmpty: + growCache gMods, fileIdx.int32 + if gMods[fileIdx.int32].reason != rrEmpty: # reason has already been computed for this module: - return gMods[fileIdx].reason + return gMods[fileIdx.int32].reason let filename = fileIdx.toFilename var hash = getHash(fileIdx) - gMods[fileIdx].reason = rrNone # we need to set it here to avoid cycles + gMods[fileIdx.int32].reason = rrNone # we need to set it here to avoid cycles result = rrNone var rodfile = toGeneratedFile(filename.withPackageName, RodExt) - var r = newRodReader(rodfile, hash, fileIdx, cache) + var r = newRodReader(rodfile, hash, fileIdx.int32, cache) if r == nil: result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist) else: @@ -907,19 +907,18 @@ proc checkDep(fileIdx: int32; cache: IdentCache): TReasonForRecompile = # recompilation is necessary: if r != nil: memfiles.close(r.memfile) r = nil - gMods[fileIdx].rd = r - gMods[fileIdx].reason = result # now we know better + gMods[fileIdx.int32].rd = r + gMods[fileIdx.int32].reason = result # now we know better proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader = - let fileIdx = module.fileIdx if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}: module.id = getID() return nil idgen.loadMaxIds(options.gProjectPath / options.gProjectName) - + let fileIdx = FileIndex module.fileIdx discard checkDep(fileIdx, cache) - if gMods[fileIdx].reason == rrEmpty: internalError("handleSymbolFile") - result = gMods[fileIdx].rd + if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile") + result = gMods[fileIdx.int32].rd if result != nil: module.id = result.moduleID result.syms[module.id] = module @@ -1153,7 +1152,7 @@ proc viewFile(rodfile: string) = if r.s[r.pos] == '\x0A': inc(r.pos) inc(r.line) - outf.write(w, " ", inclHash, "\n") + outf.write(w.int32, " ", inclHash, "\n") if r.s[r.pos] == ')': inc(r.pos) outf.write(")\n") of "DEPS": @@ -1163,7 +1162,7 @@ proc viewFile(rodfile: string) = let v = int32(decodeVInt(r.s, r.pos)) r.modDeps.add(r.files[v]) if r.s[r.pos] == ' ': inc(r.pos) - outf.write(" ", r.files[v]) + outf.write(" ", r.files[v].int32) outf.write("\n") of "INTERF", "COMPILERPROCS": inc r.pos, 2 diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 96deb1d5a7..0ae6872685 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -55,7 +55,7 @@ proc fileIdx(w: PRodWriter, filename: string): int = w.files[result] = filename template filename*(w: PRodWriter): string = - w.module.filename + toFilename(FileIndex w.module.position) proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter = new(result) @@ -125,14 +125,14 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, result.add('?') encodeVInt(n.info.col, result) result.add(',') - encodeVInt(n.info.line, result) + encodeVInt(int n.info.line, result) result.add(',') encodeVInt(fileIdx(w, toFullPath(n.info)), result) elif fInfo.line != n.info.line: result.add('?') encodeVInt(n.info.col, result) result.add(',') - encodeVInt(n.info.line, result) + encodeVInt(int n.info.line, result) elif fInfo.col != n.info.col: result.add('?') encodeVInt(n.info.col, result) @@ -303,7 +303,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = result.add('?') if s.info.col != -1'i16: encodeVInt(s.info.col, result) result.add(',') - if s.info.line != -1'i16: encodeVInt(s.info.line, result) + if s.info.line != 0'u16: encodeVInt(int s.info.line, result) result.add(',') encodeVInt(fileIdx(w, toFullPath(s.info)), result) if s.owner != nil: @@ -642,7 +642,7 @@ proc process(c: PPassContext, n: PNode): PNode = proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = if module.id < 0: internalError("rodwrite: module ID not set") - var w = newRodWriter(rodread.getHash module.fileIdx, module, cache) + var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache) rawAddInterfaceSym(w, module) result = w diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 3996188dc2..bcc1bba150 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -144,7 +144,7 @@ proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = proc filename*(c: PContext): string = # the module's filename - return c.module.filename + return toFilename(FileIndex c.module.position) proc scopeDepth*(c: PContext): int {.inline.} = result = if c.currentScope != nil: c.currentScope.depthLevel diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 75d8cc2e0a..8d7747fb4a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1095,12 +1095,12 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode = for i in 0.. 0: suggestQuit() proc suggestSentinel*(c: PContext) = - if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex: return + if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return if c.compilesContextId > 0: return inc(c.compilesContextId) var outputs: Suggestions = @[] diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 4745b1ac7d..4014d4c584 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -138,7 +138,7 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string, else: result = applyFilter(p, n, filename, result) -proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream; +proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache) = var s: PLLStream p.skin = skinStandard @@ -155,7 +155,7 @@ proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream; proc closeParsers*(p: var TParsers) = parser.closeParser(p.parser) -proc parseFile*(fileIdx: int32; cache: IdentCache): PNode {.procvar.} = +proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = var p: TParsers f: File diff --git a/compiler/vm.nim b/compiler/vm.nim index 5b5ccdce4e..70f79c433b 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1381,7 +1381,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcNGetLine: decodeB(rkNode) let n = regs[rb].node - regs[ra].node = newIntNode(nkIntLit, n.info.line) + regs[ra].node = newIntNode(nkIntLit, n.info.line.int) regs[ra].node.info = n.info regs[ra].node.typ = n.typ of opcNGetColumn: @@ -1521,7 +1521,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let x = newNodeI(TNodeKind(int(k)), if cc.kind != nkNilLit: cc.info - elif c.comesFromHeuristic.line > -1: + elif c.comesFromHeuristic.line != 0'u16: c.comesFromHeuristic elif c.callsite != nil and c.callsite.safeLen > 1: c.callsite[1].info @@ -1748,7 +1748,7 @@ proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, setupGlobalCtx(module, cache) var c = globalCtx - c.comesFromHeuristic.line = -1 + c.comesFromHeuristic.line = 0'u16 c.callsite = nOrig let start = genProc(c, sym) From 516ce7306660a183b3e81d6c2622a84b9396f3e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Sat, 21 Apr 2018 08:15:41 +0200 Subject: [PATCH 029/214] macro manual improvements (#7666) * macro manual improvements * fixes a typo * Small fixes --- doc/manual.rst | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index b114f0a8aa..9f9206e5ca 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5241,15 +5241,21 @@ chance to convert it into a sequence. Macros ====== -A macro is a special kind of low level template. Macros can be used -to implement `domain specific languages`:idx:. +A macro is a special function that is executed at compile-time. +Normally the input for a macro is an abstract syntax +tree (AST) of the code that is passed to it. The macro can then do +transformations on it and return the transformed AST. The +transformed AST is then passed to the compiler as if the macro +invocation would have been replaced by its result in the source +code. This can be used to implement `domain specific +languages`:idx:. While macros enable advanced compile-time code transformations, they cannot change Nim's syntax. However, this is no real restriction because Nim's syntax is flexible enough anyway. To write macros, one needs to know how the Nim concrete syntax is converted -to an abstract syntax tree. +to an AST. There are two ways to invoke a macro: (1) invoking a macro like a procedure call (`expression macros`) @@ -5269,19 +5275,21 @@ variable number of arguments: # ``macros`` module: import macros - macro debug(n: varargs[untyped]): untyped = - # `n` is a Nim AST that contains the whole macro invocation - # this macro returns a list of statements: - result = newNimNode(nnkStmtList, n) + macro debug(args: varargs[untyped]): untyped = + # `args` is a collection of `NimNode` values that each contain the + # AST for an argument of the macro. A macro always has to + # return a `NimNode`. A node of kind `nnkStmtList` is suitable for + # this use case. + result = nnkStmtList.newTree() # iterate over any argument that is passed to this macro: - for i in 0..n.len-1: + for n in args: # add a call to the statement list that writes the expression; # `toStrLit` converts an AST to its string representation: - add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i]))) + result.add newCall("write", newIdentNode("stdout"), newLit(n.repr)) # add a call to the statement list that writes ": " - add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": "))) + result.add newCall("write", newIdentNode("stdout"), newLit(": ")) # add a call to the statement list that writes the expressions value: - add(result, newCall("writeLine", newIdentNode("stdout"), n[i])) + result.add newCall("writeLine", newIdentNode("stdout"), n) var a: array[0..10, int] @@ -8187,5 +8195,3 @@ validation errors: If the taint mode is turned off, ``TaintedString`` is simply an alias for ``string``. - - From e44c6d833799d42fac0445cfcbf4b2e75e70358f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 21 Apr 2018 16:32:54 +0200 Subject: [PATCH 030/214] refactoring: remove dead code --- compiler/modules.nim | 105 ------------------------------------------- 1 file changed, 105 deletions(-) diff --git a/compiler/modules.nim b/compiler/modules.nim index 52a6f2fdd8..56bfdf662b 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -13,111 +13,6 @@ import ast, astalgo, magicsys, std / sha1, rodread, msgs, cgendata, sigmatch, options, idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod -when false: - type - TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled - THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged - - TModuleInMemory* = object - hash*: SecureHash - deps*: seq[int32] ## XXX: slurped files are currently not tracked - - needsRecompile*: TNeedRecompile - hashStatus*: THashStatus - - var - gCompiledModules: seq[PSym] = @[] - gMemCacheData*: seq[TModuleInMemory] = @[] - ## XXX: we should implement recycling of file IDs - ## if the user keeps renaming modules, the file IDs will keep growing - gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why. - - proc hashChanged(fileIdx: int32): bool = - internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len - - template updateStatus = - gMemCacheData[fileIdx].hashStatus = if result: hashHasChanged - else: hashNotChanged - # echo "TESTING Hash: ", fileIdx.toFilename, " ", result - - case gMemCacheData[fileIdx].hashStatus - of hashHasChanged: - result = true - of hashNotChanged: - result = false - of hashCached: - let newHash = secureHashFile(fileIdx.toFullPath) - result = newHash != gMemCacheData[fileIdx].hash - gMemCacheData[fileIdx].hash = newHash - updateStatus() - of hashNotTaken: - gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath) - result = true - updateStatus() - - proc doHash(fileIdx: int32) = - if gMemCacheData[fileIdx].hashStatus == hashNotTaken: - # echo "FIRST Hash: ", fileIdx.ToFilename - gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath) - - proc resetModule*(fileIdx: int32) = - # echo "HARD RESETTING ", fileIdx.toFilename - if fileIdx <% gMemCacheData.len: - gMemCacheData[fileIdx].needsRecompile = Yes - if fileIdx <% gCompiledModules.len: - gCompiledModules[fileIdx] = nil - if fileIdx <% cgendata.gModules.len: - cgendata.gModules[fileIdx] = nil - - proc resetModule*(module: PSym) = - let conflict = getModule(module.position.int32) - if conflict == nil: return - doAssert conflict == module - resetModule(module.position.int32) - initStrTable(module.tab) - - proc resetAllModules* = - for i in 0..gCompiledModules.high: - if gCompiledModules[i] != nil: - resetModule(i.int32) - resetPackageCache() - # for m in cgenModules(): echo "CGEN MODULE FOUND" - - proc resetAllModulesHard* = - resetPackageCache() - gCompiledModules.setLen 0 - gMemCacheData.setLen 0 - magicsys.resetSysTypes() - # XXX - #gOwners = @[] - - proc checkDepMem(fileIdx: int32): TNeedRecompile = - template markDirty = - resetModule(fileIdx) - return Yes - - if gFuzzyGraphChecking: - if gMemCacheData[fileIdx].needsRecompile != Maybe: - return gMemCacheData[fileIdx].needsRecompile - else: - # cycle detection: We claim that a cycle does no harm. - if gMemCacheData[fileIdx].needsRecompile == Probing: - return No - - if optForceFullMake in gGlobalOptions or hashChanged(fileIdx): - markDirty() - - if gMemCacheData[fileIdx].deps != nil: - gMemCacheData[fileIdx].needsRecompile = Probing - for dep in gMemCacheData[fileIdx].deps: - let d = checkDepMem(dep) - if d in {Yes, Recompiled}: - # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d - markDirty() - - gMemCacheData[fileIdx].needsRecompile = No - return No - proc resetSystemArtifacts*() = magicsys.resetSysTypes() From 4f10b5edb6a6e51da5a3f8b0156a456d6eba8727 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 21 Apr 2018 16:41:35 +0200 Subject: [PATCH 031/214] improve documentation for 'var T return values'; refs #7373 --- doc/manual.rst | 24 +++++++++++++++++++++--- doc/manual/var_t_return.rst | 20 ++++++++++++++++++++ web/website.ini | 2 +- 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 doc/manual/var_t_return.rst diff --git a/doc/manual.rst b/doc/manual.rst index 9f9206e5ca..fbd0430201 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3487,17 +3487,17 @@ returned value is an l-value and can be modified by the caller: .. code-block:: nim var g = 0 - proc WriteAccessToG(): var int = + proc writeAccessToG(): var int = result = g - WriteAccessToG() = 6 + writeAccessToG() = 6 assert g == 6 It is a compile time error if the implicitly introduced pointer could be used to access a location beyond its lifetime: .. code-block:: nim - proc WriteAccessToG(): var int = + proc writeAccessToG(): var int = var g = 0 result = g # Error! @@ -3512,6 +3512,24 @@ In the standard library every name of a routine that returns a ``var`` type starts with the prefix ``m`` per convention. +.. include:: manual/var_t_return.rst + +Future directions +~~~~~~~~~~~~~~~~~ + +Later versions of Nim can be more precise about the borrowing rule with +a syntax like: + +.. code-block:: nim + proc foo(other: Y; container: var X): var T from container + +Here ``var T from container`` explicitly exposes that the +location is deviated from the second parameter (called +'container' in this case). The syntax ``var T from p`` specifies a type +``varTy[T, 2]`` which is incompatible with ``varTy[T, 1]``. + + + Overloading of the subscript operator ------------------------------------- diff --git a/doc/manual/var_t_return.rst b/doc/manual/var_t_return.rst new file mode 100644 index 0000000000..b9ff1d8922 --- /dev/null +++ b/doc/manual/var_t_return.rst @@ -0,0 +1,20 @@ +Memory safety for returning by ``var T`` is ensured by a simple borrowing +rule: If ``result`` does not refer to a location pointing to the heap +(that is in ``result = X`` the ``X`` involves a ``ptr`` or ``ref`` access) +then it has to be deviated by the routine's first parameter: + +.. code-block:: nim + proc forward[T](x: var T): var T = + result = x # ok, deviated from the first parameter. + + proc p(param: var int): var int = + var x: int + # we know 'forward' provides a view into the location deviated by + # its first argument 'x'. + result = forward(x) # Error: location is derived from ``x`` + # which is not p's first parameter and lives + # on the stack. + +In other words, the lifetime of what ``result`` points to is attached to the +lifetime of the first parameter and that is enough knowledge to verify +memory safety at the callsite. diff --git a/web/website.ini b/web/website.ini index 56b7c436f9..18e7bf2cbf 100644 --- a/web/website.ini +++ b/web/website.ini @@ -31,7 +31,7 @@ file: ticker.html [Documentation] doc: "endb.rst;intern.txt;apis.txt;lib.rst;manual.rst;tut1.rst;tut2.rst;nimc.rst;overview.rst;filters.rst" doc: "tools.txt;niminst.rst;nimgrep.rst;gc.rst;estp.rst;idetools.rst;docgen.rst;koch.rst;backends.txt" -doc: "nimfix.rst;nimsuggest.rst;nep1.rst;nims.rst;contributing.rst" +doc: "nimfix.rst;nimsuggest.rst;nep1.rst;nims.rst;contributing.rst;manual/*.rst" pdf: "manual.rst;lib.rst;tut1.rst;tut2.rst;nimc.rst;niminst.rst;gc.rst" srcdoc2: "system.nim;system/nimscript;pure/ospaths" srcdoc2: "core/macros;pure/marshal;core/typeinfo" From 14046d975dd0c5a5195dea7d6bdcb3daa8e69eca Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 21 Apr 2018 17:01:27 +0200 Subject: [PATCH 032/214] make tests green again --- compiler/vm.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 70f79c433b..32db8f3785 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1693,7 +1693,7 @@ proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode, newSeq(tos.slots, c.prc.maxSlots) #for i in 0 ..< c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty) result = rawExecute(c, start, tos).regToNode - if result.info.line < 0: result.info = n.info + if result.info.col < 0: result.info = n.info proc evalConstExpr*(module: PSym; cache: IdentCache, e: PNode): PNode = result = evalConstExprAux(module, cache, nil, e, emConst) From 85ea9593b38351e69fedac61ff0c2b958bac4b7f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 21 Apr 2018 21:22:36 +0200 Subject: [PATCH 033/214] fixes #7637; assignments are not allowed to slice object; minor breaking change --- changelog.md | 4 ++++ lib/system/assign.nim | 10 ++++++++-- tests/objects/tinherentedvalues.nim | 16 +++++++--------- tests/objects/tobj_asgn_dont_slice.nim | 24 ++++++++++++++++++++++++ tests/objects/tobjconstr.nim | 7 +++---- 5 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 tests/objects/tobj_asgn_dont_slice.nim diff --git a/changelog.md b/changelog.md index e6d1f6b478..a3332789a3 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,10 @@ to deal with! - Indexing into a ``cstring`` for the JS target is now mapped to ``charCodeAt``. +- Assignments that would "slice" an object into its supertype are not prevented + at runtime. Use ``ref object`` with inheritance rather than ``object`` with + inheritance to prevent this issue. + #### Breaking changes in the standard library diff --git a/lib/system/assign.nim b/lib/system/assign.nim index f061c89cfe..ff1ef31d22 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -79,8 +79,12 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = GenericSeqSize), mt.base, shallow) of tyObject: - if mt.base != nil: - genericAssignAux(dest, src, mt.base, shallow) + var it = mt.base + # don't use recursion here on the PNimType because the subtype + # check should only be done at the very end: + while it != nil: + genericAssignAux(dest, src, it.node, shallow) + it = it.base genericAssignAux(dest, src, mt.node, shallow) # we need to copy m_type field for tyObject, as it could be empty for # sequence reallocations: @@ -89,6 +93,8 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = # if p of TB: # var tbObj = TB(p) # tbObj of TC # needs to be false! + #c_fprintf(stdout, "%s %s\n", pint[].name, mt.name) + chckObjAsgn(cast[ptr PNimType](src)[], mt) pint[] = mt # cast[ptr PNimType](src)[] of tyTuple: genericAssignAux(dest, src, mt.node, shallow) diff --git a/tests/objects/tinherentedvalues.nim b/tests/objects/tinherentedvalues.nim index c96a0fd6d5..ad7b5f326d 100644 --- a/tests/objects/tinherentedvalues.nim +++ b/tests/objects/tinherentedvalues.nim @@ -1,9 +1,7 @@ discard """ - output: '''tbObj of TC false -false + output: '''tbObj of TC true true -5 -false''' +5''' """ # bug #1053 @@ -20,10 +18,10 @@ type proc test(p: TA) = #echo "p of TB ", p of TB if p of TB: - var tbObj = TB(p) + #var tbObj = TB(p) # tbObj is actually no longer compatible with TC: - echo "tbObj of TC ", tbObj of TC + echo "tbObj of TC ", p of TC var v = TC() v.a = 1 @@ -48,8 +46,8 @@ proc isMyObject(obj: TObject) = asd.x = 5 -var asdCopy = TObject(asd) -echo asdCopy of MyObject +#var asdCopy = TObject(asd) +#echo asdCopy of MyObject isMyObject(asd) -isMyObject(asdCopy) +#isMyObject(asdCopy) diff --git a/tests/objects/tobj_asgn_dont_slice.nim b/tests/objects/tobj_asgn_dont_slice.nim new file mode 100644 index 0000000000..866b5aeccb --- /dev/null +++ b/tests/objects/tobj_asgn_dont_slice.nim @@ -0,0 +1,24 @@ +discard """ + outputsub: '''ObjectAssignmentError''' + exitcode: "1" +""" + +# bug #7637 +type + Fruit = object of RootObj + name*: string + Apple = object of Fruit + Pear = object of Fruit + +method eat(f: Fruit) {.base.} = + raise newException(Exception, "PURE VIRTUAL CALL") + +method eat(f: Apple) = + echo "fruity" + +method eat(f: Pear) = + echo "juicy" + +let basket = [Apple(name:"a"), Pear(name:"b")] + +eat(basket[0]) diff --git a/tests/objects/tobjconstr.nim b/tests/objects/tobjconstr.nim index d1f3c8bdb7..7238d10c76 100644 --- a/tests/objects/tobjconstr.nim +++ b/tests/objects/tobjconstr.nim @@ -9,8 +9,8 @@ discard """ (k: kindA, a: (x: "abc", z: [1, 8, 3]), method: ()) (k: kindA, a: (x: "abc", z: [1, 9, 3]), method: ()) (k: kindA, a: (x: "abc", z: [1, 10, 3]), method: ()) -(x: 123) -(x: 123) +(y: 0, x: 123) +(y: 678, x: 123) (z: 89, y: 0, x: 128) (y: 678, x: 123) (y: 678, x: 123) @@ -33,7 +33,6 @@ type `method`: TEmpty # bug #1791 proc `$`[T](s: seq[T]): string = - # XXX why is that not in the stdlib? result = "[" for i, x in s: if i > 0: result.add(", ") @@ -59,7 +58,7 @@ type # inherited fields are ignored, so no fields are set when true: var - o: A + o: B o = B(x: 123) echo o o = B(y: 678, x: 123) From 14e496fab0d42eb54be38ccfb40b65f6c1d2cdf4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 21 Apr 2018 22:49:15 +0200 Subject: [PATCH 034/214] fixes #6393 --- compiler/procfind.nim | 7 +------ compiler/types.nim | 4 ++-- tests/errmsgs/tcant_overload_by_return_type.nim | 9 +++++++++ 3 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 tests/errmsgs/tcant_overload_by_return_type.nim diff --git a/compiler/procfind.nim b/compiler/procfind.nim index 137765ddba..f7d86aaef0 100644 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -66,12 +66,10 @@ proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym = proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym = const flags = {ExactGenericParams, ExactTypeDescValues, ExactConstraints, IgnoreCC} - var it: TIdentIter - result = initIdentIter(it, scope.symbols, fn.name) while result != nil: - if result.kind == fn.kind and sameType(result.typ, fn.typ, flags): + if result.kind == fn.kind: #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): @@ -85,11 +83,8 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym = return of paramsNotEqual: discard - result = nextIdentIter(it, scope.symbols) - return nil - proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym = result = searchForProcNew(c, scope, fn) when false: diff --git a/compiler/types.nim b/compiler/types.nim index a930779bf5..4d55ac7a9a 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -777,8 +777,8 @@ proc equalParams(a, b: PNode): TParamsEquality = return paramsNotEqual # paramsIncompatible; # continue traversal! If not equal, we can return immediately; else # it stays incompatible - if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}): - if (a.sons[0].typ == nil) or (b.sons[0].typ == nil): + if not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}): + if (a.typ == nil) or (b.typ == nil): result = paramsNotEqual # one proc has a result, the other not is OK else: result = paramsIncompatible # overloading by different diff --git a/tests/errmsgs/tcant_overload_by_return_type.nim b/tests/errmsgs/tcant_overload_by_return_type.nim new file mode 100644 index 0000000000..613a896b41 --- /dev/null +++ b/tests/errmsgs/tcant_overload_by_return_type.nim @@ -0,0 +1,9 @@ +discard """ +errormsg: "overloaded 'x' leads to ambiguous calls" +line: 9 +""" + +# bug #6393 + +proc x(): int = 7 +proc x(): string = "strange" From b43025b754395cc0db632fa759e78ed9098c8add Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 21 Apr 2018 23:58:24 +0200 Subject: [PATCH 035/214] fixes #5113 --- compiler/semexprs.nim | 8 ++++++++ tests/varres/tnewseq_on_result_vart.nim | 9 +++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/varres/tnewseq_on_result_vart.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 4256e0aa68..8e223ed901 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -526,6 +526,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = if isAssignable(c, it) notin {arLValue, arLocalLValue}: if it.kind != nkHiddenAddr: localError(it.info, errVarForOutParamNeededX, $it) + # bug #5113: disallow newSeq(result) where result is a 'var T': + if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}: + var arg = n[1] #.skipAddr + if arg.kind == nkHiddenDeref: arg = arg[0] + if arg.kind == nkSym and arg.sym.kind == skResult and + arg.typ.skipTypes(abstractInst).kind in {tyVar, tyLent}: + localError(n.info, errXStackEscape, renderTree(n[1], {renderNoComments})) + return for i in countup(1, sonsLen(n) - 1): if n.sons[i].kind == nkHiddenCallConv: diff --git a/tests/varres/tnewseq_on_result_vart.nim b/tests/varres/tnewseq_on_result_vart.nim new file mode 100644 index 0000000000..18935a1d1b --- /dev/null +++ b/tests/varres/tnewseq_on_result_vart.nim @@ -0,0 +1,9 @@ + +discard """ + line: 9 + errormsg: "address of 'result' may not escape its stack frame" +""" +# bug #5113 + +proc makeSeqVar(size: Natural): var seq[int] = + newSeq(result, size) From 07f4e8a4ed2624b92a6cb5fc578e80619b947919 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 22 Apr 2018 00:12:43 +0200 Subject: [PATCH 036/214] new 'var T' error messages with hyperlinks; closes #7373 --- compiler/msgs.nim | 3 +++ compiler/semexprs.nim | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 06f333cef8..f08d2d2aff 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -10,6 +10,9 @@ import options, strutils, os, tables, ropes, platform, terminal, macros +const + explanationsBaseUrl* = "https://nim-lang.org/docs/manual" + type TMsgKind* = enum errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 8e223ed901..279b6cc577 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1342,11 +1342,11 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = let root = exprRoot(n) if root != nil and root.owner == c.p.owner: if root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags: - localError(n.info, "'$1' escapes its stack frame; context: '$2'" % [ - root.name.s, renderTree(n, {renderNoComments})]) + localError(n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [ + root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl]) elif root.kind == skParam and root.position != 0: - localError(n.info, "'$1' is not the first parameter; context: '$2'" % [ - root.name.s, renderTree(n, {renderNoComments})]) + localError(n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [ + root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl]) case n.kind of nkHiddenAddr, nkAddr: return n of nkHiddenDeref, nkDerefExpr: return n.sons[0] From 0ba50f98909b862e813da558e297ec1681fd7e7d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 22 Apr 2018 00:19:41 +0200 Subject: [PATCH 037/214] make tests green again --- tests/cpp/tcovariancerules.nim | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/tests/cpp/tcovariancerules.nim b/tests/cpp/tcovariancerules.nim index f81d67a505..acde1b2884 100644 --- a/tests/cpp/tcovariancerules.nim +++ b/tests/cpp/tcovariancerules.nim @@ -13,14 +13,8 @@ cat cat dog dog -dog value -cat value -dog value -cat value dog dog -dog value -cat value dog 1 dog 2 ''' @@ -243,11 +237,12 @@ reject modifiesCovariantArray(dogRefsArray.addr) var dogValues = @[vdog, vdog] var dogValuesArray = [vdog, vdog] -var animalValues = @[Animal(vdog), Animal(vcat)] -var animalValuesArray = [Animal(vdog), Animal(vcat)] +when false: + var animalValues = @[Animal(vdog), Animal(vcat)] + var animalValuesArray = [Animal(vdog), Animal(vcat)] -wantsNonCovariantSeq animalValues -wantsNonCovariantArray animalValuesArray + wantsNonCovariantSeq animalValues + wantsNonCovariantArray animalValuesArray reject wantsNonCovariantSeq(dogRefs) reject modifiesCovariantOperArray(dogRefs) @@ -260,7 +255,6 @@ modifiesDerivedOperArray dogRefs reject modifiesDerivedOperArray(dogValues) reject modifiesDerivedOperArray(animalRefs) -wantsNonCovariantOperArray animalValues reject wantsNonCovariantOperArray(animalRefs) reject wantsNonCovariantOperArray(dogRefs) reject wantsNonCovariantOperArray(dogValues) From 34b333b1403128b84b93b6ede6f0b1378d7e67df Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 22 Apr 2018 07:10:55 +0200 Subject: [PATCH 038/214] make tests green again --- compiler/types.nim | 2 +- tests/overload/toverprc.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 4d55ac7a9a..5d60fa9b4e 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -970,7 +970,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameFlags(a, b) of tyGenericParam: result = sameChildrenAux(a, b, c) and sameFlags(a, b) - if result and ExactGenericParams in c.flags: + if result and {ExactGenericParams, ExactTypeDescValues} * c.flags != {}: result = a.sym.position == b.sym.position of tyGenericInvocation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyLent, tySink, diff --git a/tests/overload/toverprc.nim b/tests/overload/toverprc.nim index 112eae0969..9be2203f61 100644 --- a/tests/overload/toverprc.nim +++ b/tests/overload/toverprc.nim @@ -11,7 +11,7 @@ proc parseInt(x: float): int {.noSideEffect.} = discard proc parseInt(x: bool): int {.noSideEffect.} = discard proc parseInt(x: float32): int {.noSideEffect.} = discard proc parseInt(x: int8): int {.noSideEffect.} = discard -proc parseInt(x: TFile): int {.noSideEffect.} = discard +proc parseInt(x: File): int {.noSideEffect.} = discard proc parseInt(x: char): int {.noSideEffect.} = discard proc parseInt(x: int16): int {.noSideEffect.} = discard From a8b70c550083e432f0028e6582c97d8310a48c8a Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 22 Apr 2018 23:16:14 +0200 Subject: [PATCH 039/214] remove unused error messages --- compiler/msgs.nim | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index f08d2d2aff..5ae2c49700 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -16,18 +16,18 @@ const type TMsgKind* = enum errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated, - errXCompilerDoesNotSupportCpp, errStringLiteralExpected, + errStringLiteralExpected, errIntLiteralExpected, errInvalidCharacterConstant, errClosingTripleQuoteExpected, errClosingQuoteExpected, - errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong, + errTabulatorsAreNotAllowed, errInvalidToken, errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange, errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected, errNewlineExpected, errInvalidModuleName, - errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected, + errOperatorExpected, errTokenExpected, errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected, errInvalidPragma, errUnknownPragma, errInvalidDirectiveX, errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation, - errExceptionExpected, errExceptionAlreadyHandled, + errExceptionAlreadyHandled, errYieldNotAllowedHere, errYieldNotAllowedInTryStmt, errInvalidNumberOfYieldExpr, errCannotReturnExpr, errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine, @@ -71,7 +71,7 @@ type errWrongNumberOfArgumentsInCall, errMissingGenericParamsForTemplate, errXCannotBePassedToProcVar, - errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed, + errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed, errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, errInvalidOrderInArrayConstructor, @@ -148,7 +148,6 @@ const errIllFormedAstX: "illformed AST: $1", errCannotOpenFile: "cannot open \'$1\'", errGenerated: "$1", - errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++", errStringLiteralExpected: "string literal expected", errIntLiteralExpected: "integer literal expected", errInvalidCharacterConstant: "invalid character constant", @@ -156,7 +155,6 @@ const errClosingQuoteExpected: "closing \" expected", errTabulatorsAreNotAllowed: "tabulators are not allowed", errInvalidToken: "invalid token: $1", - errLineTooLong: "line too long", errInvalidNumber: "$1 is not a valid number", errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.", errNumberOutOfRange: "number $1 out of valid range", @@ -168,7 +166,6 @@ const errInvalidModuleName: "invalid module name: '$1'", errOperatorExpected: "operator expected, but found \'$1\'", errTokenExpected: "\'$1\' expected", - errStringAfterIncludeExpected: "string after \'include\' expected", errRecursiveDependencyX: "recursive dependency: \'$1\'", errOnOrOffExpected: "\'on\' or \'off\' expected", errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected", @@ -178,7 +175,6 @@ const errAtPopWithoutPush: "\'pop\' without a \'push\' pragma", errEmptyAsm: "empty asm statement", errInvalidIndentation: "invalid indentation", - errExceptionExpected: "exception expected", errExceptionAlreadyHandled: "exception already handled", errYieldNotAllowedHere: "'yield' only allowed in an iterator", errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator", @@ -284,7 +280,6 @@ const errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar", - errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration", errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", errImplOfXexpected: "implementation of \'$1\' expected", From 72dfe176f5211f561263984a2df653f16dcf5466 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Mon, 23 Apr 2018 17:02:38 +0800 Subject: [PATCH 040/214] remove dead code elimination option (#7669) --- compiler/ast.nim | 6 +++--- compiler/ccgexprs.nim | 5 ++--- compiler/ccgstmts.nim | 18 ++---------------- compiler/ccgutils.nim | 4 ---- compiler/cgen.nim | 4 ---- compiler/commands.nim | 3 +-- compiler/options.nim | 3 ++- compiler/pragmas.nim | 14 ++++---------- compiler/wordrecg.nim | 6 ++++-- doc/basicopt.txt | 1 - doc/manual.rst | 16 ---------------- doc/nimc.rst | 4 ++-- lib/deprecated/pure/sockets.nim | 2 +- lib/impure/db_sqlite.nim | 2 +- lib/impure/rdstdin.nim | 2 +- lib/posix/epoll.nim | 2 +- lib/posix/inotify.nim | 2 +- lib/posix/kqueue.nim | 8 +++----- lib/posix/linux.nim | 2 +- lib/posix/posix.nim | 8 ++++---- lib/posix/posix_other.nim | 2 +- lib/posix/termios.nim | 2 +- lib/pure/fenv.nim | 2 +- lib/pure/matchers.nim | 2 +- lib/pure/net.nim | 2 +- lib/pure/os.nim | 2 +- lib/pure/parseutils.nim | 2 +- lib/pure/ropes.nim | 2 +- lib/pure/strmisc.nim | 2 +- lib/pure/strutils.nim | 2 +- lib/pure/unicode.nim | 2 +- lib/system.nim | 2 +- lib/windows/winlean.nim | 2 +- lib/wrappers/iup.nim | 2 +- lib/wrappers/mysql.nim | 2 +- lib/wrappers/odbcsql.nim | 2 +- lib/wrappers/openssl.nim | 2 +- lib/wrappers/pcre.nim | 2 +- lib/wrappers/postgres.nim | 2 +- lib/wrappers/sqlite3.nim | 2 +- tests/enum/toptions.nim | 2 +- tests/iter/tobj_iter.nim | 2 -- .../dependencies/chipmunk/chipmunk.nim | 1 - .../keineschweine/dependencies/enet/enet.nim | 1 - .../dependencies/genpacket/macro_dsl.nim | 2 +- .../keineschweine/dependencies/sfml/sfml.nim | 2 +- .../dependencies/sfml/sfml_colors.nim | 2 +- .../dependencies/sfml/sfml_vector.nim | 1 - tests/manyloc/keineschweine/keineschweine.nim | 2 +- tests/manyloc/keineschweine/lib/sg_gui.nim | 2 +- tests/manyloc/keineschweine/server/nim.cfg | 1 - tests/manyloc/nake/nakefile.nim | 2 +- tests/manyloc/standalone/barebone.nim.cfg | 1 - tests/pragmas/tnoreturn.nim | 7 +++++-- tests/rodfiles/deadg.nim | 3 --- tools/nim.bash-completion | 4 ++-- tools/nim.zsh-completion | 2 -- 57 files changed, 67 insertions(+), 122 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 4a0a9a20bf..2c8f686ebb 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -262,7 +262,8 @@ type # variable is a thread variable sfCompileTime, # proc can be evaluated at compile time sfConstructor, # proc is a C++ constructor - sfDeadCodeElim, # dead code elimination for the module is turned on + sfDispatcher, # copied method symbol is the dispatcher + # deprecated and unused, except for the con sfBorrow, # proc is borrowed sfInfixCall, # symbol needs infix call syntax in target language; # for interfacing with C++, JS @@ -275,10 +276,9 @@ type TSymFlags* = set[TSymFlag] const - sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher sfNoInit* = sfMainModule # don't generate code to init the variable - sfImmediate* = sfDeadCodeElim + sfImmediate* = sfDispatcher # macro or template is immediately expanded # without considering any possible overloads sfAllUntyped* = sfVolatile # macro or template is immediately expanded \ diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 461a862986..ea373f5a6a 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2264,7 +2264,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkEmpty: discard of nkWhileStmt: genWhileStmt(p, n) of nkVarSection, nkLetSection: genVarStmt(p, n) - of nkConstSection: genConstStmt(p, n) + of nkConstSection: discard # consts generated lazily on use of nkForStmt: internalError(n.info, "for statement not eliminated") of nkCaseStmt: genCase(p, n, d) of nkReturnStmt: genReturnStmt(p, n) @@ -2315,8 +2315,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = # are not transformed correctly. We work around this issue (#411) here # by ensuring it's no inner proc (owner is a module): if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags: - if (not emitLazily(prc)) or - ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or + if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or (prc.kind == skMethod): # we have not only the header: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 2030d6add2..cb3d6dbe6e 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -280,20 +280,6 @@ proc genVarStmt(p: BProc, n: PNode) = else: genVarTuple(p, it) -proc genConstStmt(p: BProc, n: PNode) = - for it in n.sons: - if it.kind == nkCommentStmt: continue - if it.kind != nkConstDef: internalError(n.info, "genConstStmt") - - let sym = it.sons[0].sym - if sym.typ.containsCompileTimeOnly or - sym.typ.kind notin ConstantDataTypes or - sym.ast.len == 0 or - emitLazily(sym): - continue - - requestConstImpl(p, sym) - proc genIf(p: BProc, n: PNode, d: var TLoc) = # # { if (!expr1) goto L1; @@ -587,7 +573,7 @@ proc genRaiseStmt(p: BProc, t: PNode) = genLineDir(p, t) if isImportedException(typ): lineF(p, cpsStmts, "throw $1;$n", [e]) - else: + else: lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n", [e, makeCString(typ.sym.name.s)]) else: @@ -836,7 +822,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = else: for j in 0..t[i].len-2: if t[i][j].isInfixAs(): - let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:` + let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:` fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnUnknown) startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, t[i][j][1].typ), rdLoc(exvar.sym.loc)) else: diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index fe28d2209b..48648bddea 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -211,8 +211,4 @@ proc mangle*(name: string): string = if requiresUnderscore: result.add "_" -proc emitLazily*(s: PSym): bool {.inline.} = - result = optDeadCodeElim in gGlobalOptions or - sfDeadCodeElim in getModule(s).flags - initTypeTables() diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 9e1f9349ff..ff3e6714d5 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1309,10 +1309,6 @@ proc newModule(g: BModuleList; module: PSym): BModule = growCache g.modules, module.position g.modules[module.position] = result - if (optDeadCodeElim in gGlobalOptions): - if (sfDeadCodeElim in module.flags): - internalError("added pending module twice: " & toFilename(FileIndex module.position)) - template injectG(config) {.dirty.} = if graph.backend == nil: graph.backend = newModuleList(config) diff --git a/compiler/commands.nim b/compiler/commands.nim index e1dc1aacf3..8d73ac90e6 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -268,7 +268,6 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool = of "movechecks": result = contains(gOptions, optMoveCheck) of "linedir": result = contains(gOptions, optLineDir) of "assertions", "a": result = contains(gOptions, optAssert) - of "deadcodeelim": result = contains(gGlobalOptions, optDeadCodeElim) of "run", "r": result = contains(gGlobalOptions, optRun) of "symbolfiles": result = gSymbolFiles != disabledSf of "genscript": result = contains(gGlobalOptions, optGenScript) @@ -509,7 +508,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "movechecks": processOnOffSwitch({optMoveCheck}, arg, pass, info) of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info) of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info) - of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info) + of "deadcodeelim": discard # deprecated, dead code elim always on of "threads": processOnOffSwitchG({optThreads}, arg, pass, info) #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe) diff --git a/compiler/options.nim b/compiler/options.nim index 93a3f17962..7126d43980 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -41,7 +41,8 @@ type # please make sure we have under 32 options TOptions* = set[TOption] TGlobalOption* = enum # **keep binary compatible** - gloptNone, optForceFullMake, optDeadCodeElim, + gloptNone, optForceFullMake, + optDeadCodeElimUnused, # deprecated, always on optListCmd, optCompileOnly, optNoLinking, optCDebug, # turn on debugging information optGenDynLib, # generate a dynamic library diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index cb11564a4c..9e9233fe72 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -44,7 +44,9 @@ const wWarnings, wHints, wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop, - wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated, + wBreakpoint, wWatchPoint, wPassl, wPassc, + wDeadCodeElimUnused, # deprecated, always on + wDeprecated, wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd, wPatterns, wEffects, wNoForward, wReorder, wComputedGoto, wInjectStmt, wDeprecated, wExperimental, wThis} @@ -215,10 +217,6 @@ proc onOff(c: PContext, n: PNode, op: TOptions) = if isTurnedOn(c, n): gOptions = gOptions + op else: gOptions = gOptions - op -proc pragmaDeadCodeElim(c: PContext, n: PNode) = - if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim) - else: excl(c.module.flags, sfDeadCodeElim) - proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) = if isTurnedOn(c, n): incl(c.module.flags, flag) else: excl(c.module.flags, flag) @@ -764,7 +762,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wThreadVar: noVal(it) incl(sym.flags, sfThread) - of wDeadCodeElim: pragmaDeadCodeElim(c, it) + of wDeadCodeElimUnused: discard # deprecated, dead code elim always on of wNoForward: pragmaNoForward(c, it) of wReorder: pragmaNoForward(c, it, sfReorder) of wMagic: processMagic(c, it, sym) @@ -960,10 +958,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, if sym.kind != skType or sym.typ == nil: invalidPragma(it) else: incl(sym.typ.flags, tfPartial) - # .partial types can only work with dead code elimination - # to prevent the codegen from doing anything before we compiled - # the whole program: - incl gGlobalOptions, optDeadCodeElim of wInject, wGensym: # We check for errors, but do nothing with these pragmas otherwise # as they are handled directly in 'evalTemplate'. diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 76d91d4e77..91b527e028 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -55,7 +55,8 @@ type wFloatchecks, wNanChecks, wInfChecks, wMoveChecks, wAssertions, wPatterns, wWarnings, wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags, - wDeadCodeElim, wSafecode, wPackage, wNoForward, wReorder, wNoRewrite, + wDeadCodeElimUnused, # deprecated, dead code elim always happens + wSafecode, wPackage, wNoForward, wReorder, wNoRewrite, wPragma, wCompileTime, wNoInit, wPassc, wPassl, wBorrow, wDiscardable, @@ -143,7 +144,8 @@ const "assertions", "patterns", "warnings", "hints", "optimization", "raises", "writes", "reads", "size", "effects", "tags", - "deadcodeelim", "safecode", "package", "noforward", "reorder", "norewrite", + "deadcodeelim", # deprecated, dead code elim always happens + "safecode", "package", "noforward", "reorder", "norewrite", "pragma", "compiletime", "noinit", "passc", "passl", "borrow", "discardable", "fieldchecks", diff --git a/doc/basicopt.txt b/doc/basicopt.txt index 4c11cc767e..90c7ba09c8 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -29,7 +29,6 @@ Options: --nanChecks:on|off turn NaN checks on|off --infChecks:on|off turn Inf checks on|off --nilChecks:on|off turn nil checks on|off - --deadCodeElim:on|off whole program dead code elimination on|off --opt:none|speed|size optimize not at all or for speed|size Note: use -d:release for a release build! --debugger:native|endb use native debugger (gdb) | ENDB (experimental) diff --git a/doc/manual.rst b/doc/manual.rst index fbd0430201..f1330d5247 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6768,22 +6768,6 @@ the created global variables within a module is not defined, but all of them will be initialized after any top-level variables in their originating module and before any variable in a module that imports it. -deadCodeElim pragma -------------------- -The ``deadCodeElim`` pragma only applies to whole modules: It tells the -compiler to activate (or deactivate) dead code elimination for the module the -pragma appears in. - -The ``--deadCodeElim:on`` command line switch has the same effect as marking -every module with ``{.deadCodeElim:on}``. However, for some modules such as -the GTK wrapper it makes sense to *always* turn on dead code elimination - -no matter if it is globally active or not. - -Example: - -.. code-block:: nim - {.deadCodeElim: on.} - .. NoForward pragma diff --git a/doc/nimc.rst b/doc/nimc.rst index b275438eaa..29dbdea429 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -181,7 +181,7 @@ generated; use the ``--symbolFiles:on`` command line switch to activate them. Unfortunately due to technical reasons the ``--symbolFiles:on`` needs to *aggregate* some generated C code. This means that the resulting executable -might contain some cruft even when dead code elimination is turned on. So +might contain some cruft even with dead code elimination. So the final release build should be done with ``--symbolFiles:off``. Due to the aggregation of C code it is also recommended that each project @@ -439,7 +439,7 @@ target. For example, to generate code for an `AVR`:idx: processor use this command:: - nim c --cpu:avr --os:standalone --deadCodeElim:on --genScript x.nim + nim c --cpu:avr --os:standalone --genScript x.nim For the ``standalone`` target one needs to provide a file ``panicoverride.nim``. diff --git a/lib/deprecated/pure/sockets.nim b/lib/deprecated/pure/sockets.nim index f0568366ab..05aebef76a 100644 --- a/lib/deprecated/pure/sockets.nim +++ b/lib/deprecated/pure/sockets.nim @@ -32,7 +32,7 @@ include "system/inclrtl" -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated when hostOS == "solaris": {.passl: "-lsocket -lnsl".} diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 21049571f9..f88037e2f3 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -81,7 +81,7 @@ ## ## theDb.close() -{.deadCodeElim:on.} +{.deadCodeElim: on.} # dce option deprecated import strutils, sqlite3 diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 5aa4cfcc38..54bab82f0b 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -13,7 +13,7 @@ ## is used. This suffices because Windows' console already provides the ## wanted functionality. -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated when defined(Windows): proc readLineFromStdin*(prompt: string): TaintedString {. diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim index c5ed1a8733..2d38137bb9 100644 --- a/lib/posix/epoll.nim +++ b/lib/posix/epoll.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -{.deadCodeElim:on.} +{.deadCodeElim: on.} # dce option deprecated from posix import SocketHandle diff --git a/lib/posix/inotify.nim b/lib/posix/inotify.nim index a206f80671..359e88617f 100644 --- a/lib/posix/inotify.nim +++ b/lib/posix/inotify.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -{.deadCodeElim:on.} +{.deadCodeElim: on.} # dce option deprecated # Get the platform-dependent flags. # Structure describing an inotify event. diff --git a/lib/posix/kqueue.nim b/lib/posix/kqueue.nim index 730491a536..18b47f5d50 100644 --- a/lib/posix/kqueue.nim +++ b/lib/posix/kqueue.nim @@ -7,8 +7,6 @@ # distribution, for details about the copyright. # -{.deadCodeElim:on.} - from posix import Timespec when defined(macosx) or defined(freebsd) or defined(openbsd) or @@ -61,7 +59,7 @@ const EV_CLEAR* = 0x0020 ## Clear event state after reporting. EV_RECEIPT* = 0x0040 ## Force EV_ERROR on success, data == 0 EV_DISPATCH* = 0x0080 ## Disable event after reporting. - + EV_SYSFLAGS* = 0xF000 ## Reserved by system EV_DROP* = 0x1000 ## Not should be dropped EV_FLAG1* = 0x2000 ## Filter-specific flag @@ -87,10 +85,10 @@ when defined(macosx) or defined(freebsd) or defined(dragonfly): NOTE_FFAND* = 0x40000000'u32 ## AND fflags NOTE_FFOR* = 0x80000000'u32 ## OR fflags NOTE_FFCOPY* = 0xc0000000'u32 ## copy fflags - NOTE_FFCTRLMASK* = 0xc0000000'u32 ## masks for operations + NOTE_FFCTRLMASK* = 0xc0000000'u32 ## masks for operations NOTE_FFLAGSMASK* = 0x00ffffff'u32 - NOTE_TRIGGER* = 0x01000000'u32 ## Cause the event to be triggered + NOTE_TRIGGER* = 0x01000000'u32 ## Cause the event to be triggered ## for output. # data/hint flags for EVFILT_{READ|WRITE}, shared with userspace diff --git a/lib/posix/linux.nim b/lib/posix/linux.nim index 6f9f75e340..25c7c79793 100644 --- a/lib/posix/linux.nim +++ b/lib/posix/linux.nim @@ -1,4 +1,4 @@ -{.deadCodeElim:on.} +{.deadCodeElim: on.} # dce option deprecated import posix diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index a23d760509..3ff156bdf0 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -27,10 +27,10 @@ ## resulting C code will just ``#include `` and *not* define the ## symbols declared here. -# This ensures that we don't accidentally generate #includes for files that -# might not exist on a specific platform! The user will get an error only -# if they actualy try to use the missing declaration -{.deadCodeElim: on.} +# Dead code elimination ensures that we don't accidentally generate #includes +# for files that might not exist on a specific platform! The user will get an +# error only if they actualy try to use the missing declaration +{.deadCodeElim: on.} # dce option deprecated # TODO these constants don't seem to be fetched from a header file for unknown # platforms - where do they come from and why are they here? diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index ae41263e81..004a4205b3 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -{.deadCodeElim:on.} +{.deadCodeElim: on.} # dce option deprecated const hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index f86e408fb3..60d5401077 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated import posix type diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim index f8f115eccc..a083c680ce 100644 --- a/lib/pure/fenv.nim +++ b/lib/pure/fenv.nim @@ -10,7 +10,7 @@ ## Floating-point environment. Handling of floating-point rounding and ## exceptions (overflow, division by zero, etc.). -{.deadCodeElim:on.} +{.deadCodeElim: on.} # dce option deprecated when defined(Posix) and not defined(haiku): {.passl: "-lm".} diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim index 6366fee1ab..685c3b07ac 100644 --- a/lib/pure/matchers.nim +++ b/lib/pure/matchers.nim @@ -12,7 +12,7 @@ ## **Warning:** This module is deprecated since version 0.14.0. {.deprecated.} -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated {.push debugger:off .} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ccf02a1fca..ebb59ca6d6 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -68,7 +68,7 @@ ## ``newSocket()``. The difference is that the latter creates a new file ## descriptor. -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated import nativesockets, os, strutils, parseutils, times, sets, options export Port, `$`, `==` export Domain, SockType, Protocol diff --git a/lib/pure/os.nim b/lib/pure/os.nim index ddeee2c6b2..11be8f0c12 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -10,7 +10,7 @@ ## This module contains basic operating system facilities like ## retrieving environment variables, reading command line arguments, ## working with directories, running shell commands, etc. -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated {.push debugger: off.} diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 57387e62ed..cecc94e925 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -11,7 +11,7 @@ ## ## To unpack raw bytes look at the `streams `_ module. -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated {.push debugger:off .} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 6ddd61afa6..24ba012e5f 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -19,7 +19,7 @@ include "system/inclrtl" import streams -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated {.push debugger:off .} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/strmisc.nim b/lib/pure/strmisc.nim index 89ef2fcd20..d1ff920c93 100644 --- a/lib/pure/strmisc.nim +++ b/lib/pure/strmisc.nim @@ -12,7 +12,7 @@ import strutils -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated proc expandTabs*(s: string, tabSize: int = 8): string {.noSideEffect, procvar.} = diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 54fdcb4d0b..849c16c345 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -17,7 +17,7 @@ import parseutils from math import pow, round, floor, log10 from algorithm import reverse -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated {.push debugger:off .} # the user does not want to trace a part # of the standard library! diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 257c620f79..cc4d28f5ba 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -9,7 +9,7 @@ ## This module provides support to handle the Unicode UTF-8 encoding. -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated include "system/inclrtl" diff --git a/lib/system.nim b/lib/system.nim index 5e08dadc0b..874b8c4d13 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -146,7 +146,7 @@ proc declared*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} ## # missing it. when defined(useNimRtl): - {.deadCodeElim: on.} + {.deadCodeElim: on.} # dce option deprecated proc definedInScope*(x: untyped): bool {. magic: "DefinedInScope", noSideEffect, deprecated, compileTime.} diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 62bc38da9e..7e22f98c7c 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -10,7 +10,7 @@ ## This module implements a small wrapper for some needed Win API procedures, ## so that the Nim compiler does not depend on the huge Windows module. -{.deadCodeElim:on.} +{.deadCodeElim: on.} # dce option deprecated import dynlib diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim index d910173cad..dee2e14c71 100644 --- a/lib/wrappers/iup.nim +++ b/lib/wrappers/iup.nim @@ -34,7 +34,7 @@ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # **************************************************************************** -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated when defined(windows): const dllname = "iup(|30|27|26|25|24).dll" diff --git a/lib/wrappers/mysql.nim b/lib/wrappers/mysql.nim index 4464eae508..06c663822e 100644 --- a/lib/wrappers/mysql.nim +++ b/lib/wrappers/mysql.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated {.push, callconv: cdecl.} when defined(Unix): diff --git a/lib/wrappers/odbcsql.nim b/lib/wrappers/odbcsql.nim index 1b2544ec01..43d1c504df 100644 --- a/lib/wrappers/odbcsql.nim +++ b/lib/wrappers/odbcsql.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated when not defined(ODBCVER): const diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 357343bffb..86ae853696 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -22,7 +22,7 @@ ## ./bin/nim c -d:ssl -p:. -r tests/untestable/tssl.nim ## ./bin/nim c -d:ssl -p:. --dynlibOverride:ssl --passL:-lcrypto --passL:-lssl -r tests/untestable/tssl.nim -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated const useWinVersion = defined(Windows) or defined(nimdoc) diff --git a/lib/wrappers/pcre.nim b/lib/wrappers/pcre.nim index 6c7088bbf2..e9e11960c8 100644 --- a/lib/wrappers/pcre.nim +++ b/lib/wrappers/pcre.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated # The current PCRE version information. diff --git a/lib/wrappers/postgres.nim b/lib/wrappers/postgres.nim index f9a10dccbf..7cb816f689 100644 --- a/lib/wrappers/postgres.nim +++ b/lib/wrappers/postgres.nim @@ -15,7 +15,7 @@ # connection-protocol. # -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated when defined(windows): const diff --git a/lib/wrappers/sqlite3.nim b/lib/wrappers/sqlite3.nim index a129458323..0276a0a652 100644 --- a/lib/wrappers/sqlite3.nim +++ b/lib/wrappers/sqlite3.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -{.deadCodeElim: on.} +{.deadCodeElim: on.} # dce option deprecated when defined(windows): when defined(nimOldDlls): const Lib = "sqlite3.dll" diff --git a/tests/enum/toptions.nim b/tests/enum/toptions.nim index e53acb2b35..da66f0067c 100644 --- a/tests/enum/toptions.nim +++ b/tests/enum/toptions.nim @@ -4,7 +4,7 @@ type TOption = enum optNone, optForceFullMake, optBoehmGC, optRefcGC, optRangeCheck, optBoundsCheck, optOverflowCheck, optNilCheck, optAssert, optLineDir, - optWarns, optHints, optDeadCodeElim, optListCmd, optCompileOnly, + optWarns, optHints, optListCmd, optCompileOnly, optSafeCode, # only allow safe code optStyleCheck, optOptimizeSpeed, optOptimizeSize, optGenDynLib, optGenGuiApp, optStackTrace diff --git a/tests/iter/tobj_iter.nim b/tests/iter/tobj_iter.nim index eb0e37b23b..a894755d71 100644 --- a/tests/iter/tobj_iter.nim +++ b/tests/iter/tobj_iter.nim @@ -4,8 +4,6 @@ discard """ # bug #2023 -{.deadCodeElim:on.} - type Obj = object iter: iterator (): int8 {.closure.} diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim index 56d3edec49..f06c4e0be3 100644 --- a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim +++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim @@ -23,7 +23,6 @@ const Lib = "libchipmunk.so.6.1.1" when defined(MoreNim): {.hint: "MoreNim defined; some Chipmunk functions replaced in Nim".} -{.deadCodeElim: on.} from math import sqrt, sin, cos, arctan2 when defined(CpUseFloat): {.hint: "CpUseFloat defined; using float32 as float".} diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim index 3c4ce2017a..3ea8172d5f 100644 --- a/tests/manyloc/keineschweine/dependencies/enet/enet.nim +++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim @@ -20,7 +20,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. const Lib = "libenet.so.1(|.0.3)" -{.deadCodeElim: on.} const ENET_VERSION_MAJOR* = 1 ENET_VERSION_MINOR* = 3 diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim index d3a0c701d3..86c12fbb09 100644 --- a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim +++ b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim @@ -1,5 +1,5 @@ import macros -{.deadCodeElim: on.} + #Inline macro.add() to allow for easier nesting proc und*(a: NimNode; b: NimNode): NimNode {.compileTime.} = a.add(b) diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim index 1524f0eb46..0060bf12bd 100644 --- a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim @@ -12,7 +12,7 @@ else: LibS = "libcsfml-system.so.2.0" LibW = "libcsfml-window.so.2.0" #{.error: "Platform unsupported".} -{.deadCodeElim: on.} + {.pragma: pf, pure, final.} type PClock* = ptr TClock diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim index 95a760e1ff..b4eb1b8f06 100644 --- a/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim @@ -1,5 +1,5 @@ import sfml -{.deadCodeElim: on.} + let Black*: TColor = color(0, 0, 0) White*: TColor = color(255, 255, 255) diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim index 474d249aa1..94c5308a99 100644 --- a/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim @@ -1,2 +1 @@ import sfml, math, strutils -{.deadCodeElim: on.} diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim index c0f1bc0313..59347ee46d 100644 --- a/tests/manyloc/keineschweine/keineschweine.nim +++ b/tests/manyloc/keineschweine/keineschweine.nim @@ -5,7 +5,7 @@ import sg_gui, sg_assets, sound_buffer, enet_client when defined(profiler): import nimprof -{.deadCodeElim: on.} + type PPlayer* = ref TPlayer TPlayer* = object diff --git a/tests/manyloc/keineschweine/lib/sg_gui.nim b/tests/manyloc/keineschweine/lib/sg_gui.nim index ffc4e8215b..b7448d9df4 100644 --- a/tests/manyloc/keineschweine/lib/sg_gui.nim +++ b/tests/manyloc/keineschweine/lib/sg_gui.nim @@ -2,7 +2,7 @@ import sfml, sfml_colors, input_helpers, sg_packets from strutils import countlines -{.deadCodeElim: on.} + type PGuiContainer* = ref TGuiContainer TGuiContainer* = object of TObject diff --git a/tests/manyloc/keineschweine/server/nim.cfg b/tests/manyloc/keineschweine/server/nim.cfg index fdc45a8e18..211ad3003b 100644 --- a/tests/manyloc/keineschweine/server/nim.cfg +++ b/tests/manyloc/keineschweine/server/nim.cfg @@ -1,5 +1,4 @@ debugger = off -deadCodeElim = on path = ".." path = "../genpacket" path = "../helpers" diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim index 2055d78346..97af79a84f 100644 --- a/tests/manyloc/nake/nakefile.nim +++ b/tests/manyloc/nake/nakefile.nim @@ -10,7 +10,7 @@ const ExeName = "keineschweine" ServerDefines = "-d:NoSFML -d:NoChipmunk" TestBuildDefines = "-d:escapeMenuTest -d:debugWeps -d:showFPS -d:moreNim -d:debugKeys -d:foo -d:recordMode --forceBuild" - ReleaseDefines = "-d:release --deadCodeElim:on" + ReleaseDefines = "-d:release" ReleaseTestDefines = "-d:debugWeps -d:debugKeys --forceBuild" task "testprofile", "..": diff --git a/tests/manyloc/standalone/barebone.nim.cfg b/tests/manyloc/standalone/barebone.nim.cfg index bb350ff553..b956bef8e9 100644 --- a/tests/manyloc/standalone/barebone.nim.cfg +++ b/tests/manyloc/standalone/barebone.nim.cfg @@ -1,3 +1,2 @@ --os:standalone ---deadCodeElim:on --gc:none diff --git a/tests/pragmas/tnoreturn.nim b/tests/pragmas/tnoreturn.nim index 4d00c60346..bb59b1c71a 100644 --- a/tests/pragmas/tnoreturn.nim +++ b/tests/pragmas/tnoreturn.nim @@ -2,13 +2,16 @@ discard """ ccodeCheck: "\\i @'__attribute__((noreturn))' .*" """ -proc noret1*(i: int) {.noreturn.} = +proc noret1*(i: int) {.noreturn.} = echo i -proc noret2*(i: int): void {.noreturn.} = +proc noret2*(i: int): void {.noreturn.} = echo i +noret1(1) +noret2(2) + var p {.used.}: proc(i: int): int doAssert(not compiles( p = proc(i: int): int {.noreturn.} = i # noreturn lambda returns int diff --git a/tests/rodfiles/deadg.nim b/tests/rodfiles/deadg.nim index 587608e14e..0aee59bb80 100644 --- a/tests/rodfiles/deadg.nim +++ b/tests/rodfiles/deadg.nim @@ -1,6 +1,3 @@ - -{.deadCodeElim: on.} - proc p1*(x, y: int): int = result = x + y diff --git a/tools/nim.bash-completion b/tools/nim.bash-completion index 1c199a0cfa..8e569079ac 100644 --- a/tools/nim.bash-completion +++ b/tools/nim.bash-completion @@ -15,7 +15,7 @@ _nim() return 0 fi case $prev in - --stackTrace|--lineTrace|--threads|-x|--checks|--objChecks|--fieldChecks|--rangeChecks|--boundChecks|--overflowChecks|-a|--assertions|--floatChecks|--nanChecks|--infChecks|--deadCodeElim) + --stackTrace|--lineTrace|--threads|-x|--checks|--objChecks|--fieldChecks|--rangeChecks|--boundChecks|--overflowChecks|-a|--assertions|--floatChecks|--nanChecks|--infChecks) # Options that require on/off [[ "$cur" == "=" ]] && cur="" COMPREPLY=( $(compgen -W 'on off' -- "$cur") ) @@ -32,7 +32,7 @@ _nim() return 0 ;; *) - kw="-r -p= --path= -d= --define= -u= --undef= -f --forceBuild --opt= --app= --stackTrace= --lineTrace= --threads= -x= --checks= --objChecks= --fieldChecks= --rangeChecks= --boundChecks= --overflowChecks= -a= --assertions= --floatChecks= --nanChecks= --infChecks= --deadCodeElim=" + kw="-r -p= --path= -d= --define= -u= --undef= -f --forceBuild --opt= --app= --stackTrace= --lineTrace= --threads= -x= --checks= --objChecks= --fieldChecks= --rangeChecks= --boundChecks= --overflowChecks= -a= --assertions= --floatChecks= --nanChecks= --infChecks=" COMPREPLY=( $( compgen -W "${kw}" -- $cur ) ) _filedir '@(nim)' #$split diff --git a/tools/nim.zsh-completion b/tools/nim.zsh-completion index 57b5e163ec..e9b9002fb5 100644 --- a/tools/nim.zsh-completion +++ b/tools/nim.zsh-completion @@ -60,8 +60,6 @@ _nim() { '*--infChecks=off[turn Inf checks off]' \ '*--nilChecks=on[turn nil checks on]' \ '*--nilChecks=off[turn nil checks off]' \ - '*--deadCodeElim=on[whole program dead code elimination on]' \ - '*--deadCodeElim=off[whole program dead code elimination off]' \ '*--opt=none[do not optimize]' \ '*--opt=speed[optimize for speed|size - use -d:release for a release build]' \ '*--opt=size[optimize for size]' \ From 8caf257607e0b76f103155add7849fb934371678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Mon, 23 Apr 2018 11:09:48 +0200 Subject: [PATCH 041/214] Don't escape multibyte characters (#7570) --- compiler/renderer.nim | 33 +++------------ lib/pure/strutils.nim | 17 ++++++-- lib/system.nim | 42 +++++++++++++++----- tests/collections/tcollections_to_string.nim | 10 ++++- 4 files changed, 60 insertions(+), 42 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 0e631a8986..2a65a10a80 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -172,32 +172,6 @@ proc put(g: var TSrcGen, kind: TTokType, s: string) = else: g.pendingWhitespace = s.len -proc addNimChar(dst: var string; c: char): void = - case c - of '\0': dst.add "\\x00" # not "\\0" to avoid ambiguous cases like "\\012". - of '\a': dst.add "\\a" # \x07 - of '\b': dst.add "\\b" # \x08 - of '\t': dst.add "\\t" # \x09 - of '\L': dst.add "\\L" # \x0A - of '\v': dst.add "\\v" # \x0B - of '\f': dst.add "\\f" # \x0C - of '\c': dst.add "\\c" # \x0D - of '\e': dst.add "\\e" # \x1B - of '\x01'..'\x06', '\x0E'..'\x1A', '\x1C'..'\x1F', '\x80'..'\xFF': - dst.add "\\x" - dst.add strutils.toHex(ord(c), 2) - of '\'', '\"', '\\': - dst.add '\\' - dst.add c - else: - dst.add c - -proc makeNimString(s: string): string = - result = "\"" - for c in s: - result.addNimChar c - add(result, '\"') - proc putComment(g: var TSrcGen, s: string) = if s.isNil: return var i = 0 @@ -365,10 +339,13 @@ proc atom(g: TSrcGen; n: PNode): string = of nkEmpty: result = "" of nkIdent: result = n.ident.s of nkSym: result = n.sym.name.s - of nkStrLit: result = makeNimString(n.strVal) + of nkStrLit: result = ""; result.addQuoted(n.strVal) of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"' of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\"" - of nkCharLit: result = "\'"; result.addNimChar chr(int(n.intVal)); result.add '\'' + of nkCharLit: + result = "\'" + result.addEscapedChar(chr(int(n.intVal))); + result.add '\'' of nkIntLit: result = litAux(g, n, n.intVal, 4) of nkInt8Lit: result = litAux(g, n, n.intVal, 1) & "\'i8" of nkInt16Lit: result = litAux(g, n, n.intVal, 2) & "\'i16" diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 849c16c345..cdc5ec4f9d 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1818,20 +1818,29 @@ proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect, dec(L) proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, - rtl, extern: "nsuEscape".} = + rtl, extern: "nsuEscape", deprecated.} = ## Escapes a string `s`. See `system.addEscapedChar `_ ## for the escaping scheme. ## ## The resulting string is prefixed with `prefix` and suffixed with `suffix`. ## Both may be empty strings. + ## + ## **Warning:** This procedure is deprecated because it's to easy to missuse. result = newStringOfCap(s.len + s.len shr 2) result.add(prefix) for c in items(s): - result.addEscapedChar(c) + case c + of '\0'..'\31', '\127'..'\255': + add(result, "\\x") + add(result, toHex(ord(c), 2)) + of '\\': add(result, "\\\\") + of '\'': add(result, "\\'") + of '\"': add(result, "\\\"") + else: add(result, c) add(result, suffix) proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, - rtl, extern: "nsuUnescape".} = + rtl, extern: "nsuUnescape", deprecated.} = ## Unescapes a string `s`. ## ## This complements `escape <#escape>`_ as it performs the opposite @@ -1839,6 +1848,8 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, ## ## If `s` does not begin with ``prefix`` and end with ``suffix`` a ## ValueError exception will be raised. + ## + ## **Warning:** This procedure is deprecated because it's to easy to missuse. result = newStringOfCap(s.len) var i = prefix.len if not s.startsWith(prefix): diff --git a/lib/system.nim b/lib/system.nim index 874b8c4d13..98c1334281 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3933,29 +3933,48 @@ proc addEscapedChar*(s: var string, c: char) {.noSideEffect, inline.} = ## * replaces any ``\`` by ``\\`` ## * replaces any ``'`` by ``\'`` ## * replaces any ``"`` by ``\"`` - ## * replaces any other character in the set ``{'\0'..'\31', '\127'..'\255'}`` + ## * replaces any ``\a`` by ``\\a`` + ## * replaces any ``\b`` by ``\\b`` + ## * replaces any ``\t`` by ``\\t`` + ## * replaces any ``\n`` by ``\\n`` + ## * replaces any ``\v`` by ``\\v`` + ## * replaces any ``\f`` by ``\\f`` + ## * replaces any ``\c`` by ``\\c`` + ## * replaces any ``\e`` by ``\\e`` + ## * replaces any other character not in the set ``{'\21..'\126'} ## by ``\xHH`` where ``HH`` is its hexadecimal value. ## ## The procedure has been designed so that its output is usable for many ## different common syntaxes. ## **Note**: This is not correct for producing Ansi C code! case c - of '\0'..'\31', '\127'..'\255': - add(s, "\\x") + of '\a': s.add "\\a" # \x07 + of '\b': s.add "\\b" # \x08 + of '\t': s.add "\\t" # \x09 + of '\n': s.add "\\n" # \x0A + of '\v': s.add "\\v" # \x0B + of '\f': s.add "\\f" # \x0C + of '\c': s.add "\\c" # \x0D + of '\e': s.add "\\e" # \x1B + of '\\': s.add("\\\\") + of '\'': s.add("\\'") + of '\"': s.add("\\\"") + of {'\32'..'\126'} - {'\\', '\'', '\"'}: s.add(c) + else: + s.add("\\x") const HexChars = "0123456789ABCDEF" let n = ord(c) s.add(HexChars[int((n and 0xF0) shr 4)]) s.add(HexChars[int(n and 0xF)]) - of '\\': add(s, "\\\\") - of '\'': add(s, "\\'") - of '\"': add(s, "\\\"") - else: add(s, c) proc addQuoted*[T](s: var string, x: T) = ## Appends `x` to string `s` in place, applying quoting and escaping ## if `x` is a string or char. See ## `addEscapedChar `_ - ## for the escaping scheme. + ## for the escaping scheme. When `x` is a string, characters in the + ## range ``{\128..\255}`` are never escaped so that multibyte UTF-8 + ## characters are untouched (note that this behavior is different from + ## ``addEscapedChar``). ## ## The Nim standard library uses this function on the elements of ## collections when producing a string representation of a collection. @@ -3974,7 +3993,12 @@ proc addQuoted*[T](s: var string, x: T) = when T is string: s.add("\"") for c in x: - s.addEscapedChar(c) + # Only ASCII chars are escaped to avoid butchering + # multibyte UTF-8 characters. + if c <= 127.char: + s.addEscapedChar(c) + else: + s.add c s.add("\"") elif T is char: s.add("'") diff --git a/tests/collections/tcollections_to_string.nim b/tests/collections/tcollections_to_string.nim index 6cc8a84ff0..48b06a6aa0 100644 --- a/tests/collections/tcollections_to_string.nim +++ b/tests/collections/tcollections_to_string.nim @@ -85,14 +85,20 @@ block: s.addQuoted('\0') s.addQuoted('\31') s.addQuoted('\127') - s.addQuoted('\255') - doAssert s == "'\\x00''\\x1F''\\x7F''\\xFF'" + doAssert s == "'\\x00''\\x1F''\\x7F'" block: var s = "" s.addQuoted('\\') s.addQuoted('\'') s.addQuoted('\"') doAssert s == """'\\''\'''\"'""" +block: + var s = "" + s.addQuoted("å") + s.addQuoted("ä") + s.addQuoted("ö") + s.addEscapedChar('\xFF') + doAssert s == """"å""ä""ö"\xFF""" # Test customized element representation type CustomString = object From 64908bf171ac3f8cd4c81a6de0e512e47d1d5d5d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 23 Apr 2018 10:37:19 +0200 Subject: [PATCH 042/214] nimgrep: add --filenames option --- tools/nimgrep.nim | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 8dc076ad98..4cfcbe9bc2 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -11,7 +11,7 @@ import os, strutils, parseopt, pegs, re, terminal const - Version = "1.1" + Version = "1.2" Usage = "nimgrep - Nim Grep Utility Version " & Version & """ (c) 2012 Andreas Rumpf @@ -35,6 +35,8 @@ Options: --nocolor output will be given without any colours. --oneline show file on each matched line --verbose be verbose: list every processed file + --filenames find the pattern in the filenames, not in the contents + of the file --help, -h shows this help --version, -v shows the version """ @@ -42,7 +44,7 @@ Options: type TOption = enum optFind, optReplace, optPeg, optRegex, optRecursive, optConfirm, optStdin, - optWord, optIgnoreCase, optIgnoreStyle, optVerbose + optWord, optIgnoreCase, optIgnoreStyle, optVerbose, optFilenames TOptions = set[TOption] TConfirmEnum = enum ceAbort, ceYes, ceAll, ceNo, ceNone @@ -135,11 +137,14 @@ proc processFile(pattern; filename: string) = filenameShown = true var buffer: string - try: - buffer = system.readFile(filename) - except IOError: - echo "cannot open file: ", filename - return + if optFilenames in options: + buffer = filename + else: + try: + buffer = system.readFile(filename) + except IOError: + echo "cannot open file: ", filename + return if optVerbose in options: stdout.writeLine(filename) stdout.flushFile() @@ -293,6 +298,7 @@ for kind, key, val in getopt(): of "nocolor": useWriteStyled = false of "oneline": oneline = true of "verbose": incl(options, optVerbose) + of "filenames": incl(options, optFilenames) of "help", "h": writeHelp() of "version", "v": writeVersion() else: writeHelp() @@ -304,6 +310,7 @@ when defined(posix): checkOptions({optFind, optReplace}, "find", "replace") checkOptions({optPeg, optRegex}, "peg", "re") checkOptions({optIgnoreCase, optIgnoreStyle}, "ignore_case", "ignore_style") +checkOptions({optFilenames, optReplace}, "filenames", "replace") if optStdin in options: pattern = ask("pattern [ENTER to exit]: ") From ba86b09e69e4c7cb6bc906f1f1db918547854161 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 23 Apr 2018 10:53:56 +0200 Subject: [PATCH 043/214] remove obsolete nimrod.cfg configuration files --- compiler/nimconf.nim | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index c19b41af1c..bdf5581341 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -247,10 +247,6 @@ proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) = var projectConfig = changeFileExt(gProjectFull, "nimcfg") if not fileExists(projectConfig): projectConfig = changeFileExt(gProjectFull, "nim.cfg") - if not fileExists(projectConfig): - projectConfig = changeFileExt(gProjectFull, "nimrod.cfg") - if fileExists(projectConfig): - rawMessage(warnDeprecated, projectConfig) readConfigFile(projectConfig, cache, config) proc loadConfigs*(cfg: string; config: ConfigRef = nil) = From 3e5192b5dafcfc93fae701d6cdf5ffa3d1a81e1f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 23 Apr 2018 10:54:26 +0200 Subject: [PATCH 044/214] compiler: remove unnecessary FileIndex type conversions --- compiler/passes.nim | 2 +- compiler/reorder.nim | 2 +- compiler/rodread.nim | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/passes.nim b/compiler/passes.nim index d7c1816768..6ff3f2bb5d 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -166,7 +166,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, p: TParsers a: TPassContextArray s: PLLStream - fileIdx = FileIndex module.fileIdx + fileIdx = module.fileIdx if module.id < 0: # new module caching mechanism: for i in 0.. Date: Tue, 24 Apr 2018 08:25:00 +0200 Subject: [PATCH 045/214] xmltree: remove usage of deprecated callsite() --- lib/pure/xmltree.nim | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 45696c80c8..a6f62abce7 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -12,9 +12,9 @@ import macros, strtabs type - XmlNode* = ref XmlNodeObj ## an XML tree consists of ``PXmlNode``'s. + XmlNode* = ref XmlNodeObj ## an XML tree consists of ``XmlNode``'s. - XmlNodeKind* = enum ## different kinds of ``PXmlNode``'s + XmlNodeKind* = enum ## different kinds of ``XmlNode``'s xnText, ## a text element xnElement, ## an element with 0 or more children xnCData, ## a CDATA node @@ -315,9 +315,7 @@ proc newXmlTree*(tag: string, children: openArray[XmlNode], for i in 0..children.len-1: result.s[i] = children[i] result.fAttr = attributes -proc xmlConstructor(e: NimNode): NimNode {.compileTime.} = - expectLen(e, 2) - var a = e[1] +proc xmlConstructor(a: NimNode): NimNode {.compileTime.} = if a.kind == nnkCall: result = newCall("newXmlTree", toStrLit(a[0])) var attrs = newNimNode(nnkBracket, a) @@ -348,7 +346,6 @@ macro `<>`*(x: untyped): untyped = ## ## Nim rules. ## - let x = callsite() result = xmlConstructor(x) proc child*(n: XmlNode, name: string): XmlNode = From ee366f17469a96b418b58db17e03c892cf4f17d8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 24 Apr 2018 09:34:20 +0200 Subject: [PATCH 046/214] .experimental can now be used to enable specific features --- changelog.md | 6 ++++ compiler/commands.nim | 39 ++++++++++++-------- compiler/nim.nim | 4 +-- compiler/options.nim | 14 ++++++-- compiler/pragmas.nim | 22 +++++++++--- compiler/scriptconfig.nim | 6 ++-- compiler/semasgn.nim | 4 +-- compiler/semcall.nim | 2 +- compiler/semdata.nim | 6 ++-- compiler/semexprs.nim | 6 ++-- compiler/semstmts.nim | 71 ++++++++++++------------------------- compiler/semtypinst.nim | 4 +-- compiler/service.nim | 12 +++---- compiler/transf.nim | 6 ++-- doc/advopt.txt | 5 +-- doc/manual.rst | 21 +++++------ nimsuggest/nimsuggest.nim | 8 ++--- tests/parallel/tparfind.nim | 2 +- 18 files changed, 122 insertions(+), 116 deletions(-) diff --git a/changelog.md b/changelog.md index a3332789a3..8ac02a388a 100644 --- a/changelog.md +++ b/changelog.md @@ -102,4 +102,10 @@ - Added ``macros.getProjectPath`` and ``ospaths.putEnv`` procs to Nim's virtual machine. +- The ``deadCodeElim`` option is now always turned on and the switch has no + effect anymore, but is recognized for backwards compatibility. + +- ``experimental`` is now a pragma / command line switch that can enable specific + language extensions, it is not an all-or-nothing switch anymore. + ### Bugfixes diff --git a/compiler/commands.nim b/compiler/commands.nim index 8d73ac90e6..dc5d808ecd 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -46,9 +46,9 @@ type passCmd2, # second pass over the command line passPP # preprocessor called processCommand() -proc processCommand*(switch: string, pass: TCmdLinePass) +proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef = nil) + config: ConfigRef) # implementation @@ -58,7 +58,13 @@ const const Usage = slurp"../doc/basicopt.txt".replace("//", "") - AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") + FeatureDesc = block: + var x = "" + for f in low(Feature)..high(Feature): + if x.len > 0: x.add "|" + x.add $f + x + AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") % FeatureDesc proc getCommandLineDesc(): string = result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, @@ -276,7 +282,6 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool = of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation) of "implicitstatic": result = contains(gOptions, optImplicitStatic) of "patterns": result = contains(gOptions, optPatterns) - of "experimental": result = gExperimentalMode of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace) else: invalidCmdLineOption(passCmd1, switch, info) @@ -339,7 +344,7 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = options.inclDynlibOverride(arg) proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef = nil) = + config: ConfigRef) = var theOS: TSystemOS cpu: TSystemCPU @@ -694,8 +699,13 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; # only supported for compatibility. Does nothing. expectArg(switch, arg, pass, info) of "experimental": - expectNoArg(switch, arg, pass, info) - gExperimentalMode = true + if arg.len == 0: + config.features.incl oldExperimentalFeatures + else: + try: + config.features.incl parseEnum[Feature](arg) + except ValueError: + localError(info, "unknown experimental feature") of "nocppexceptions": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optNoCppExceptions) @@ -706,7 +716,8 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; config.cppDefine(arg) of "newruntime": expectNoArg(switch, arg, pass, info) - newDestructors = true + doAssert(config != nil) + incl(config.features, destructor) defineSymbol("nimNewRuntime") of "cppcompiletonamespace": expectNoArg(switch, arg, pass, info) @@ -716,10 +727,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) else: invalidCmdLineOption(pass, switch, info) -proc processCommand(switch: string, pass: TCmdLinePass) = +proc processCommand(switch: string, pass: TCmdLinePass; config: ConfigRef) = var cmd, arg: string splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) - processSwitch(cmd, arg, pass, gCmdLineInfo) + processSwitch(cmd, arg, pass, gCmdLineInfo, config) var @@ -727,19 +738,19 @@ var # the arguments to be passed to the program that # should be run -proc processSwitch*(pass: TCmdLinePass; p: OptParser) = +proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) = # 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) + processSwitch(key, val, pass, gCmdLineInfo, config) else: - processSwitch(p.key, p.val, pass, gCmdLineInfo) + processSwitch(p.key, p.val, pass, gCmdLineInfo, config) proc processArgument*(pass: TCmdLinePass; p: OptParser; - argsCount: var int): bool = + argsCount: var int; config: ConfigRef): bool = if argsCount == 0: # nim filename.nims is the same as "nim e filename.nims": if p.key.endswith(".nims"): diff --git a/compiler/nim.nim b/compiler/nim.nim index 8f3463be98..3fa733303e 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -42,7 +42,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = writeCommandLineUsage() else: # Process command line arguments: - processCmdLine(passCmd1, "") + processCmdLine(passCmd1, "", config) if gProjectName == "-": gProjectName = "stdinfile" gProjectFull = "stdinfile" @@ -71,7 +71,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = # now process command line arguments again, because some options in the # command line can overwite the config file's settings extccomp.initVars() - processCmdLine(passCmd2, "") + processCmdLine(passCmd2, "", config) if options.command == "": rawMessage(errNoCommand, command) mainCommand(newModuleGraph(config), cache) diff --git a/compiler/options.nim b/compiler/options.nim index 7126d43980..24c9d0f734 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -103,13 +103,23 @@ type ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, ideHighlight, ideOutline, ideKnown, ideMsg + Feature* = enum ## experimental features + implicitDeref, + dotOperators, + callOperator, + parallel, + destructor + ConfigRef* = ref object ## eventually all global configuration should be moved here cppDefines*: HashSet[string] headerFile*: string + features*: set[Feature] + +const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} proc newConfigRef*(): ConfigRef = result = ConfigRef(cppDefines: initSet[string](), - headerFile: "") + headerFile: "", features: {}) proc cppDefine*(c: ConfigRef; define: string) = c.cppDefines.incl define @@ -146,8 +156,6 @@ var gListFullPaths*: bool gPreciseStack*: bool = false gNoNimblePath* = false - gExperimentalMode*: bool - newDestructors*: bool gDynlibOverrideAll*: bool useNimNamespace*: bool diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 9e9233fe72..5aa9037719 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -680,6 +680,22 @@ proc semCustomPragma(c: PContext, n: PNode): PNode = elif n.kind == nkExprColonExpr: result.kind = n.kind # pragma(arg) -> pragma: arg +proc processExperimental(c: PContext; n: PNode; s: PSym) = + if not isTopLevel(c): + localError(n.info, "'experimental' pragma only valid as toplevel statement") + if n.kind notin nkPragmaCallKinds or n.len != 2: + c.features.incl oldExperimentalFeatures + else: + n[1] = c.semConstExpr(c, n[1]) + case n[1].kind + of nkStrLit, nkRStrLit, nkTripleStrLit: + try: + c.features.incl parseEnum[Feature](n[1].strVal) + except ValueError: + localError(n[1].info, "unknown experimental feature") + else: + localError(n.info, errStringLiteralExpected) + proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, validPragmas: TSpecialWords): bool = var it = n.sons[i] @@ -993,11 +1009,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: it.sons[1] = c.semExpr(c, it.sons[1]) of wExperimental: - noVal(it) - if isTopLevel(c): - c.module.flags.incl sfExperimental - else: - localError(it.info, "'experimental' pragma only valid as toplevel statement") + processExperimental(c, it, sym) of wThis: if it.kind in nkPragmaCallKinds and it.len == 2: c.selfName = considerQuotedIdent(it[1]) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 692a8d8964..c533f4cb44 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -26,7 +26,7 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) = setResult(a, result) proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; - config: ConfigRef = nil): PEvalContext = + config: ConfigRef): PEvalContext = # For Nimble we need to export 'setupVM'. result = newCtx(module, cache) result.mode = emRepl @@ -128,7 +128,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; cbconf getCommand: setResult(a, options.command) cbconf switch: - processSwitch(a.getString 0, a.getString 1, passPP, module.info) + processSwitch(a.getString 0, a.getString 1, passPP, module.info, config) cbconf hintImpl: processSpecificNote(a.getString 0, wHint, passPP, module.info, a.getString 1) @@ -150,7 +150,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; options.cppDefine(config, a.getString(0)) proc runNimScript*(cache: IdentCache; scriptName: string; - freshDefines=true; config: ConfigRef=nil) = + freshDefines=true; config: ConfigRef) = rawMessage(hintConf, scriptName) passes.gIncludeFile = includeModule passes.gImportModule = importModule diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index bbd2baf6e0..5c7b91f6df 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -101,7 +101,7 @@ proc newOpCall(op: PSym; x: PNode): PNode = proc destructorCall(c: PContext; op: PSym; x: PNode): PNode = result = newNodeIT(nkCall, x.info, op.typ.sons[0]) result.add(newSymNode(op)) - if newDestructors: + if destructor in c.features: result.add genAddr(c, x) else: result.add x @@ -319,7 +319,7 @@ proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) = ## In the semantic pass this is called in strategic places ## to ensure we lift assignment, destructors and moves properly. ## The later 'destroyer' pass depends on it. - if not newDestructors or not hasDestructor(typ): return + if destructor notin c.features or not hasDestructor(typ): return when false: # do not produce wrong liftings while we're still instantiating generics: # now disabled; breaks topttree.nim! diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 0fc12f164e..f443339f59 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -434,7 +434,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, "Non-matching candidates for " & renderTree(n) & "\n" & candidates) result = semResolvedCall(c, n, r) - elif experimentalMode(c) and canDeref(n): + elif implicitDeref in c.features and canDeref(n): # try to deref the first argument and then try overloading resolution again: # # XXX: why is this here? diff --git a/compiler/semdata.nim b/compiler/semdata.nim index bcc1bba150..8159abf8f9 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -130,6 +130,7 @@ type signatures*: TStrTable recursiveDep*: string suggestionsMade*: bool + features*: set[Feature] inTypeContext*: int typesWithOps*: seq[(PType, PType)] #\ # We need to instantiate the type bound ops lazily after @@ -225,7 +226,7 @@ proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext result.graph = graph initStrTable(result.signatures) result.typesWithOps = @[] - + result.features = graph.config.features proc inclSym(sq: var TSymSeq, s: PSym) = var L = len(sq) @@ -398,6 +399,3 @@ proc checkMinSonsLen*(n: PNode, length: int) = proc isTopLevel*(c: PContext): bool {.inline.} = result = c.currentScope.depthLevel <= 2 - -proc experimentalMode*(c: PContext): bool {.inline.} = - result = gExperimentalMode or sfExperimental in c.module.flags diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 279b6cc577..6ad5d931d4 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -663,7 +663,7 @@ proc resolveIndirectCall(c: PContext; n, nOrig: PNode; matches(c, n, nOrig, result) if result.state != csMatch: # try to deref the first argument: - if experimentalMode(c) and canDeref(n): + if implicitDeref in c.features and canDeref(n): n.sons[1] = n.sons[1].tryDeref initCandidate(c, result, t) matches(c, n, nOrig, result) @@ -1452,7 +1452,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = typeMismatch(n.info, lhs.typ, rhsTyp) n.sons[1] = fitNode(c, le, rhs, n.info) - if not newDestructors: + if destructor notin c.features: if tfHasAsgn in lhs.typ.flags and not lhsIsResult and mode != noOverloadedAsgn: return overloadedAsgn(c, lhs, n.sons[1]) @@ -1884,7 +1884,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) result.typ = getSysType(tyString) of mParallel: - if not experimentalMode(c): + if parallel notin c.features: localError(n.info, "use the {.experimental.} pragma to enable 'parallel'") result = setMs(n, s) var x = n.lastSon diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 8d7747fb4a..94090852f8 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -385,30 +385,9 @@ proc checkNilable(v: PSym) = include semasgn proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) = - # consider this: - # var - # x = 0 - # withOverloadedAssignment = foo() - # y = use(withOverloadedAssignment) - # We need to split this into a statement list with multiple 'var' sections - # in order for this transformation to be correct. let L = identDefs.len let value = identDefs[L-1] - if value.typ != nil and tfHasAsgn in value.typ.flags and not newDestructors: - # the spec says we need to rewrite 'var x = T()' to 'var x: T; x = T()': - identDefs.sons[L-1] = emptyNode - if result.kind != nkStmtList: - let oldResult = result - oldResult.add identDefs - result = newNodeI(nkStmtList, result.info) - result.add oldResult - else: - let o = copyNode(orig) - o.add identDefs - result.add o - for i in 0 .. L-3: - result.add overloadedAsgn(c, identDefs[i], value) - elif result.kind == nkStmtList: + if result.kind == nkStmtList: let o = copyNode(orig) o.add identDefs result.add o @@ -1267,9 +1246,6 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = gp = newNodeI(nkGenericParams, n.info) if n.sons[paramsPos].kind != nkEmpty: - #if n.kind == nkDo and not experimentalMode(c): - # localError(n.sons[paramsPos].info, - # "use the {.experimental.} pragma to enable 'do' with parameters") semParamList(c, n.sons[paramsPos], gp, s) # paramsTypeCheck(c, s.typ) if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty: @@ -1363,27 +1339,26 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) = proc semOverride(c: PContext, s: PSym, n: PNode) = case s.name.s.normalize - of "destroy", "=destroy": - if newDestructors: - let t = s.typ - var noError = false - if t.len == 2 and t.sons[0] == nil and t.sons[1].kind == tyVar: - var obj = t.sons[1].sons[0] - while true: - incl(obj.flags, tfHasAsgn) - if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon - elif obj.kind == tyGenericInvocation: obj = obj.sons[0] - else: break - if obj.kind in {tyObject, tyDistinct}: - if obj.destructor.isNil: - obj.destructor = s - else: - localError(n.info, errGenerated, - "cannot bind another '" & s.name.s & "' to: " & typeToString(obj)) - noError = true - if not noError and sfSystemModule notin s.owner.flags: - localError(n.info, errGenerated, - "signature for '" & s.name.s & "' must be proc[T: object](x: var T)") + of "=destroy": + let t = s.typ + var noError = false + if t.len == 2 and t.sons[0] == nil and t.sons[1].kind == tyVar: + var obj = t.sons[1].sons[0] + while true: + incl(obj.flags, tfHasAsgn) + if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon + elif obj.kind == tyGenericInvocation: obj = obj.sons[0] + else: break + if obj.kind in {tyObject, tyDistinct}: + if obj.destructor.isNil: + obj.destructor = s + else: + localError(n.info, errGenerated, + "cannot bind another '" & s.name.s & "' to: " & typeToString(obj)) + noError = true + if not noError and sfSystemModule notin s.owner.flags: + localError(n.info, errGenerated, + "signature for '" & s.name.s & "' must be proc[T: object](x: var T)") incl(s.flags, sfUsed) of "deepcopy", "=deepcopy": if s.typ.len == 2 and @@ -1612,9 +1587,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, s.options = gOptions if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) if s.name.s[0] in {'.', '('}: - if s.name.s in [".", ".()", ".="] and not experimentalMode(c) and not newDestructors: + if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}: message(n.info, warnDeprecated, "overloaded '.' and '()' operators are now .experimental; " & s.name.s) - elif s.name.s == "()" and not experimentalMode(c): + elif s.name.s == "()" and callOperator notin c.features: message(n.info, warnDeprecated, "overloaded '()' operators are now .experimental; " & s.name.s) if n.sons[bodyPos].kind != nkEmpty: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 09434c925b..c97c1186ea 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -368,7 +368,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = assert newbody.kind in {tyRef, tyPtr} assert newbody.lastSon.typeInst == nil newbody.lastSon.typeInst = result - if newDestructors: + if destructor in cl.c.features: cl.c.typesWithOps.add((newbody, result)) else: typeBound(cl.c, newbody, result, assignment, cl.info) @@ -545,7 +545,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = else: discard proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) = - if not newDestructors: return + if destructor notin c.features: return var i = 0 while i < c.typesWithOps.len: let (newty, oldty) = c.typesWithOps[i] diff --git a/compiler/service.nim b/compiler/service.nim index ac04b78602..7cdfc112cc 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -26,7 +26,7 @@ var # 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? -proc processCmdLine*(pass: TCmdLinePass, cmd: string) = +proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) = var p = parseopt.initOptParser(cmd) var argsCount = 0 while true: @@ -36,19 +36,19 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = of cmdLongoption, cmdShortOption: if p.key == " ": p.key = "-" - if processArgument(pass, p, argsCount): break + if processArgument(pass, p, argsCount, config): break else: - processSwitch(pass, p) + processSwitch(pass, p, config) of cmdArgument: - if processArgument(pass, p, argsCount): break + if processArgument(pass, p, argsCount, config): break if pass == passCmd2: if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run": rawMessage(errArgsNeedRunOption, []) -proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}) = +proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; config: ConfigRef) = template execute(cmd) = curCaasCmd = cmd - processCmdLine(passCmd2, cmd) + processCmdLine(passCmd2, cmd, config) action(cache) gErrorCounter = 0 diff --git a/compiler/transf.nim b/compiler/transf.nim index f30f8583a9..f7ec6c97f2 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -979,7 +979,7 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = #result = liftLambdas(prc, result) when useEffectSystem: trackProc(prc, result) result = liftLocalsIfRequested(prc, result) - if c.needsDestroyPass and newDestructors: + if c.needsDestroyPass: #and newDestructors: result = injectDestructorCalls(prc, result) incl(result.flags, nfTransf) #if prc.name.s == "testbody": @@ -996,7 +996,7 @@ proc transformStmt*(module: PSym, n: PNode): PNode = when useEffectSystem: trackTopLevelStmt(module, result) #if n.info ?? "temp.nim": # echo renderTree(result, {renderIds}) - if c.needsDestroyPass and newDestructors: + if c.needsDestroyPass: result = injectDestructorCalls(module, result) incl(result.flags, nfTransf) @@ -1007,6 +1007,6 @@ proc transformExpr*(module: PSym, n: PNode): PNode = var c = openTransf(module, "") result = processTransf(c, n, module) liftDefer(c, result) - if c.needsDestroyPass and newDestructors: + if c.needsDestroyPass: result = injectDestructorCalls(module, result) incl(result.flags, nfTransf) diff --git a/doc/advopt.txt b/doc/advopt.txt index bf7dd7fb4f..0d1578f78f 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -35,7 +35,7 @@ Advanced options: --noLinking compile Nim and generated files but do not link --noMain do not generate a main procedure --genScript generate a compile script (in the 'nimcache' - subdirectory named 'compile_$project$scriptext') + subdirectory named 'compile_$$project$$scriptext') --genDeps generate a '.deps' file containing the dependencies --os:SYMBOL set the target operating system (cross-compilation) --cpu:SYMBOL set the target processor (cross-compilation) @@ -88,5 +88,6 @@ Advanced options: --parallelBuild:0|1|... perform a parallel build value = number of processors (0 for auto-detect) --verbosity:0|1|2|3 set Nim's verbosity level (1 is default) - --experimental enable experimental language features + --experimental:$1 + enable experimental language feature -v, --version show detailed version information diff --git a/doc/manual.rst b/doc/manual.rst index f1330d5247..636bf796be 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1397,10 +1397,10 @@ dereferencing operations for reference types: Automatic dereferencing is also performed for the first argument of a routine call. But currently this feature has to be only enabled -via ``{.experimental.}``: +via ``{.experimental: "implicitDeref".}``: .. code-block:: nim - {.experimental.} + {.experimental: "implicitDeref".} proc depth(x: NodeObj): int = ... @@ -5588,7 +5588,7 @@ dot operators ------------- **Note**: Dot operators are still experimental and so need to be enabled -via ``{.experimental.}``. +via ``{.experimental: "dotOperators".}``. Nim offers a special family of dot operators that can be used to intercept and rewrite proc call and field access attempts, referring @@ -6885,17 +6885,12 @@ is uncertain (it may be removed any time). Example: .. code-block:: nim - {.experimental.} - type - FooId = distinct int - BarId = distinct int - using - foo: FooId - bar: BarId + {.experimental: "parallel".} proc useUsing(bar, foo) = - echo "bar is of type BarId" - echo "foo is of type FooId" + parallel: + for i in 0..4: + echo "echo in parallel" Implementation Specific Pragmas @@ -7917,7 +7912,7 @@ Example: # Compute PI in an inefficient way import strutils, math, threadpool - {.experimental.} + {.experimental: "parallel".} proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 49e61b9a9a..b2764e9ee0 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -518,7 +518,7 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) = close(requests) close(results) -proc processCmdLine*(pass: TCmdLinePass, cmd: string) = +proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) = var p = parseopt.initOptParser(cmd) while true: parseopt.next(p) @@ -562,7 +562,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = gRefresh = true of "maxresults": suggestMaxResults = parseInt(p.val) - else: processSwitch(pass, p) + else: processSwitch(pass, p, config) of cmdArgument: let a = unixToNativePath(p.key) if dirExists(a) and not fileExists(a.addFileExt("nim")): @@ -577,7 +577,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = if paramCount() == 0: stdout.writeline(Usage) else: - processCmdLine(passCmd1, "") + processCmdLine(passCmd1, "", config) if gMode != mstdin: msgs.writelnHook = proc (msg: string) = discard if gProjectName != "": @@ -616,7 +616,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config) extccomp.initVars() - processCmdLine(passCmd2, "") + processCmdLine(passCmd2, "", config) let graph = newModuleGraph(config) graph.suggestMode = true diff --git a/tests/parallel/tparfind.nim b/tests/parallel/tparfind.nim index 9de5012f58..4b3610c670 100644 --- a/tests/parallel/tparfind.nim +++ b/tests/parallel/tparfind.nim @@ -4,7 +4,7 @@ discard """ import threadpool, sequtils -{.experimental.} +{.experimental: "parallel".} proc linearFind(a: openArray[int]; x, offset: int): int = for i, y in a: From 7df892db9dcfff24be8f0a3c0bff01643d649049 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 24 Apr 2018 11:45:08 +0200 Subject: [PATCH 047/214] make tests green again --- tests/assign/toverload_asgn1.nim | 1 + tests/assign/toverload_asgn2.nim | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/assign/toverload_asgn1.nim b/tests/assign/toverload_asgn1.nim index dbc3a71c4e..01e7e7aa7a 100644 --- a/tests/assign/toverload_asgn1.nim +++ b/tests/assign/toverload_asgn1.nim @@ -14,6 +14,7 @@ GenericT[T] '=' bool GenericT[T] '=' bool GenericT[T] '=' bool GenericT[T] '=' bool''' + disabled: "true" """ import typetraits diff --git a/tests/assign/toverload_asgn2.nim b/tests/assign/toverload_asgn2.nim index 243c904947..1104be92b5 100644 --- a/tests/assign/toverload_asgn2.nim +++ b/tests/assign/toverload_asgn2.nim @@ -1,6 +1,7 @@ discard """ output: '''i value 88 2aa''' + disabled: "true" """ import moverload_asgn2 From b503ca03f697d7364efe0bc5cf367e9e8bd12418 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 24 Apr 2018 11:58:18 +0200 Subject: [PATCH 048/214] refactoring: move 'argument' global into config object --- compiler/commands.nim | 9 ++------- compiler/nim.nim | 6 +++--- compiler/options.nim | 2 ++ compiler/service.nim | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index dc5d808ecd..591bf8883d 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -733,11 +733,6 @@ proc processCommand(switch: string, pass: TCmdLinePass; config: ConfigRef) = processSwitch(cmd, arg, pass, gCmdLineInfo, config) -var - arguments* = "" - # the arguments to be passed to the program that - # should be run - proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) = # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") # we fix this here @@ -756,7 +751,7 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser; if p.key.endswith(".nims"): options.command = "e" options.gProjectName = unixToNativePath(p.key) - arguments = cmdLineRest(p) + config.arguments = cmdLineRest(p) result = true elif pass != passCmd2: options.command = p.key @@ -765,6 +760,6 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser; if argsCount == 1: # support UNIX style filenames everywhere for portable build scripts: options.gProjectName = unixToNativePath(p.key) - arguments = cmdLineRest(p) + config.arguments = cmdLineRest(p) result = true inc argsCount diff --git a/compiler/nim.nim b/compiler/nim.nim index 3fa733303e..2807823303 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -80,7 +80,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = if msgs.gErrorCounter == 0: when hasTinyCBackend: if gCmd == cmdRun: - tccgen.run(commands.arguments) + tccgen.run(config.arguments) if optRun in gGlobalOptions: if gCmd == cmdCompileToJS: var ex: string @@ -89,7 +89,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = else: ex = quoteShell( completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir)) - execExternalProgram(findNodeJs() & " " & ex & ' ' & commands.arguments) + execExternalProgram(findNodeJs() & " " & ex & ' ' & config.arguments) else: var binPath: string if options.outFile.len > 0: @@ -99,7 +99,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = # Figure out ourselves a valid binary name. binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir var ex = quoteShell(binPath) - execExternalProgram(ex & ' ' & commands.arguments) + execExternalProgram(ex & ' ' & config.arguments) when declared(GC_setMaxPause): GC_setMaxPause 2_000 diff --git a/compiler/options.nim b/compiler/options.nim index 24c9d0f734..a5dfaa81cc 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -114,6 +114,8 @@ type cppDefines*: HashSet[string] headerFile*: string features*: set[Feature] + arguments*: string ## the arguments to be passed to the program that + ## should be run const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} diff --git a/compiler/service.nim b/compiler/service.nim index 7cdfc112cc..6ec9b90467 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -42,7 +42,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) = of cmdArgument: if processArgument(pass, p, argsCount, config): break if pass == passCmd2: - if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run": + if optRun notin gGlobalOptions and config.arguments.len > 0 and options.command.normalize != "run": rawMessage(errArgsNeedRunOption, []) proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; config: ConfigRef) = From c461811bde431f8ab566aae11116a21af2e7d50a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Wed, 25 Apr 2018 02:29:47 +0200 Subject: [PATCH 049/214] Use safeLen in pairs iterator for PNode (#7684) --- compiler/ast.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 2c8f686ebb..b8202abe60 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1622,7 +1622,7 @@ iterator items*(n: PNode): PNode = for i in 0..= nkNone and n.kind <= nkNilLit From c385391ffd08d61738392efa2be334b2ceb5517f Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 25 Apr 2018 01:41:16 +0100 Subject: [PATCH 050/214] Consts in fenv (#7688) * Fixes #7574 * better comments * Changes vars to consts for side effect tracking * Revert unintended changes --- lib/pure/fenv.nim | 53 +++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim index a083c680ce..c946c42618 100644 --- a/lib/pure/fenv.nim +++ b/lib/pure/fenv.nim @@ -102,32 +102,33 @@ proc feupdateenv*(envp: ptr Tfenv): cint {.importc, header: "".} ## represented by object pointed to by `envp` and raise exceptions ## according to saved exceptions. -var FP_RADIX_INTERNAL {. importc: "FLT_RADIX" header: "" .} : int +const + FLT_RADIX = 2 ## the radix of the exponent representation -template fpRadix* : int = FP_RADIX_INTERNAL + FLT_MANT_DIG = 24 ## the number of base FLT_RADIX digits in the mantissa part of a float + FLT_DIG = 6 ## the number of digits of precision of a float + FLT_MIN_EXP = -125 # the minimum value of base FLT_RADIX in the exponent part of a float + FLT_MAX_EXP = 128 # the maximum value of base FLT_RADIX in the exponent part of a float + FLT_MIN_10_EXP = -37 ## the minimum value in base 10 of the exponent part of a float + FLT_MAX_10_EXP = 38 ## the maximum value in base 10 of the exponent part of a float + FLT_MIN = 1.17549435e-38'f32 ## the minimum value of a float + FLT_MAX = 3.40282347e+38'f32 ## the maximum value of a float + FLT_EPSILON = 1.19209290e-07'f32 ## the difference between 1 and the least value greater than 1 of a float + + DBL_MANT_DIG = 53 ## the number of base FLT_RADIX digits in the mantissa part of a double + DBL_DIG = 15 ## the number of digits of precision of a double + DBL_MIN_EXP = -1021 ## the minimum value of base FLT_RADIX in the exponent part of a double + DBL_MAX_EXP = 1024 ## the maximum value of base FLT_RADIX in the exponent part of a double + DBL_MIN_10_EXP = -307 ## the minimum value in base 10 of the exponent part of a double + DBL_MAX_10_EXP = 308 ## the maximum value in base 10 of the exponent part of a double + DBL_MIN = 2.2250738585072014E-308 ## the minimal value of a double + DBL_MAX = 1.7976931348623157E+308 ## the minimal value of a double + DBL_EPSILON = 2.2204460492503131E-16 ## the difference between 1 and the least value greater than 1 of a double + +template fpRadix* : int = FLT_RADIX ## The (integer) value of the radix used to represent any floating ## point type on the architecture used to build the program. -var FLT_MANT_DIG {. importc: "FLT_MANT_DIG" header: "" .} : int -var FLT_DIG {. importc: "FLT_DIG" header: "" .} : int -var FLT_MIN_EXP {. importc: "FLT_MIN_EXP" header: "" .} : int -var FLT_MAX_EXP {. importc: "FLT_MAX_EXP" header: "" .} : int -var FLT_MIN_10_EXP {. importc: "FLT_MIN_10_EXP" header: "" .} : int -var FLT_MAX_10_EXP {. importc: "FLT_MAX_10_EXP" header: "" .} : int -var FLT_MIN {. importc: "FLT_MIN" header: "" .} : cfloat -var FLT_MAX {. importc: "FLT_MAX" header: "" .} : cfloat -var FLT_EPSILON {. importc: "FLT_EPSILON" header: "" .} : cfloat - -var DBL_MANT_DIG {. importc: "DBL_MANT_DIG" header: "" .} : int -var DBL_DIG {. importc: "DBL_DIG" header: "" .} : int -var DBL_MIN_EXP {. importc: "DBL_MIN_EXP" header: "" .} : int -var DBL_MAX_EXP {. importc: "DBL_MAX_EXP" header: "" .} : int -var DBL_MIN_10_EXP {. importc: "DBL_MIN_10_EXP" header: "" .} : int -var DBL_MAX_10_EXP {. importc: "DBL_MAX_10_EXP" header: "" .} : int -var DBL_MIN {. importc: "DBL_MIN" header: "" .} : cdouble -var DBL_MAX {. importc: "DBL_MAX" header: "" .} : cdouble -var DBL_EPSILON {. importc: "DBL_EPSILON" header: "" .} : cdouble - template mantissaDigits*(T : typedesc[float32]) : int = FLT_MANT_DIG ## Number of digits (in base ``floatingPointRadix``) in the mantissa ## of 32-bit floating-point numbers. @@ -179,3 +180,11 @@ template maximumPositiveValue*(T : typedesc[float64]) : float64 = DBL_MAX template epsilon*(T : typedesc[float64]): float64 = DBL_EPSILON ## The difference between 1.0 and the smallest number greater than ## 1.0 that can be represented in a 64-bit floating-point type. + + +when isMainModule: + func is_significant(x: float): bool = + if x > minimumPositiveValue(float) and x < maximumPositiveValue(float): true + else: false + + doAssert is_significant(10.0) From b34580fd5b955dec510f1aa06c3db1e4af052ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Wed, 25 Apr 2018 02:43:26 +0200 Subject: [PATCH 051/214] Rename `Time.nanoseconds` to `nanosecond` (#7673) * Rename `Time.nanoseconds` to `nanosecond` * Fix bug with Duration comparision --- lib/pure/random.nim | 2 +- lib/pure/times.nim | 60 ++++++++++++++++++++--------------------- tests/stdlib/ttimes.nim | 8 ++++-- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 968a326d24..01ea9c845f 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -192,7 +192,7 @@ when not defined(nimscript): ## Initializes the random number generator with a "random" ## number, i.e. a tickcount. Note: Does not work for NimScript. let now = times.getTime() - randomize(convert(Seconds, Nanoseconds, now.toUnix) + now.nanoseconds) + randomize(convert(Seconds, Nanoseconds, now.toUnix) + now.nanosecond) {.pop.} diff --git a/lib/pure/times.nim b/lib/pure/times.nim index bf63ed3442..7d101beab4 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -103,7 +103,7 @@ type Time* = object ## Represents a point in time. seconds: int64 - nanoseconds: NanosecondRange + nanosecond: NanosecondRange DateTime* = object of RootObj ## Represents a time in different parts. ## Although this type can represent leap @@ -159,7 +159,7 @@ type ## This type should be prefered over ``TimeInterval`` unless ## non-static time units is needed. seconds: int64 - nanoseconds: NanosecondRange + nanosecond: NanosecondRange TimeUnit* = enum ## Different units of time. Nanoseconds, Microseconds, Milliseconds, Seconds, Minutes, Hours, Days, Weeks, Months, Years @@ -223,21 +223,21 @@ proc normalize[T: Duration|Time](seconds, nanoseconds: int64): T = ## a ``Duration`` or ``Time``. A normalized ``Duration|Time`` has a ## positive nanosecond part in the range ``NanosecondRange``. result.seconds = seconds + convert(Nanoseconds, Seconds, nanoseconds) - var nanoseconds = nanoseconds mod convert(Seconds, Nanoseconds, 1) - if nanoseconds < 0: - nanoseconds += convert(Seconds, Nanoseconds, 1) + var nanosecond = nanoseconds mod convert(Seconds, Nanoseconds, 1) + if nanosecond < 0: + nanosecond += convert(Seconds, Nanoseconds, 1) result.seconds -= 1 - result.nanoseconds = nanoseconds.int + result.nanosecond = nanosecond.int -proc initTime*(unix: int64, nanoseconds: NanosecondRange): Time = +proc initTime*(unix: int64, nanosecond: NanosecondRange): Time = ## Create a ``Time`` from a unix timestamp and a nanosecond part. result.seconds = unix - result.nanoseconds = nanoseconds + result.nanosecond = nanosecond -proc nanoseconds*(time: Time): NanosecondRange = +proc nanosecond*(time: Time): NanosecondRange = ## Get the fractional part of a ``Time`` as the number ## of nanoseconds of the second. - time.nanoseconds + time.nanosecond proc initDuration*(nanoseconds, microseconds, milliseconds, seconds, minutes, hours, days, weeks: int64 = 0): Duration = @@ -281,7 +281,7 @@ proc milliseconds*(dur: Duration): int {.inline.} = runnableExamples: let dur = initDuration(seconds = 1, milliseconds = 1) doAssert dur.milliseconds == 1 - convert(Nanoseconds, Milliseconds, dur.nanoseconds) + convert(Nanoseconds, Milliseconds, dur.nanosecond) proc microseconds*(dur: Duration): int {.inline.} = ## Number of whole microseconds represented by the **fractional** @@ -289,7 +289,7 @@ proc microseconds*(dur: Duration): int {.inline.} = runnableExamples: let dur = initDuration(seconds = 1, microseconds = 1) doAssert dur.microseconds == 1 - convert(Nanoseconds, Microseconds, dur.nanoseconds) + convert(Nanoseconds, Microseconds, dur.nanosecond) proc nanoseconds*(dur: Duration): int {.inline.} = ## Number of whole nanoseconds represented by the **fractional** @@ -297,14 +297,14 @@ proc nanoseconds*(dur: Duration): int {.inline.} = runnableExamples: let dur = initDuration(seconds = 1, nanoseconds = 1) doAssert dur.nanoseconds == 1 - dur.nanoseconds + dur.nanosecond proc fractional*(dur: Duration): Duration {.inline.} = ## The fractional part of duration, as a duration. runnableExamples: let dur = initDuration(seconds = 1, nanoseconds = 5) doAssert dur.fractional == initDuration(nanoseconds = 5) - initDuration(nanoseconds = dur.nanoseconds) + initDuration(nanoseconds = dur.nanosecond) const DurationZero* = initDuration() ## Zero value for durations. Useful for comparisons. ## @@ -322,7 +322,7 @@ proc `$`*(dur: Duration): string = doAssert $initDuration(milliseconds = -1500) == "-1 second and -500 milliseconds" var parts = newSeq[string]() var remS = dur.seconds - var remNs = dur.nanoseconds.int + var remNs = dur.nanosecond.int # Normally ``nanoseconds`` should always be positive, but # that makes no sense when printing. @@ -387,7 +387,7 @@ proc fromWinTime*(win: int64): Time = proc toWinTime*(t: Time): int64 = ## Convert ``t`` to a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``). - result = t.seconds * rateDiff + epochDiff + t.nanoseconds div 100 + result = t.seconds * rateDiff + epochDiff + t.nanosecond div 100 proc isLeapYear*(year: int): bool = ## Returns true if ``year`` is a leap year. @@ -473,21 +473,21 @@ proc localZoneInfoFromTz(adjTime: Time): ZonedTime {.tags: [], raises: [], benig {. pragma: operator, rtl, noSideEffect, benign .} template subImpl[T: Duration|Time](a: Duration|Time, b: Duration|Time): T = - normalize[T](a.seconds - b.seconds, a.nanoseconds - b.nanoseconds) + normalize[T](a.seconds - b.seconds, a.nanosecond - b.nanosecond) template addImpl[T: Duration|Time](a: Duration|Time, b: Duration|Time): T = - normalize[T](a.seconds + b.seconds, a.nanoseconds + b.nanoseconds) + normalize[T](a.seconds + b.seconds, a.nanosecond + b.nanosecond) template ltImpl(a: Duration|Time, b: Duration|Time): bool = a.seconds < b.seconds or ( - a.seconds == b.seconds and a.nanoseconds < b.nanoseconds) + a.seconds == b.seconds and a.nanosecond < b.nanosecond) template lqImpl(a: Duration|Time, b: Duration|Time): bool = - a.seconds <= b.seconds or ( - a.seconds == b.seconds and a.nanoseconds <= b.seconds) + a.seconds < b.seconds or ( + a.seconds == b.seconds and a.nanosecond <= b.nanosecond) template eqImpl(a: Duration|Time, b: Duration|Time): bool = - a.seconds == b.seconds and a.nanoseconds == b.nanoseconds + a.seconds == b.seconds and a.nanosecond == b.nanosecond proc `+`*(a, b: Duration): Duration {.operator.} = ## Add two durations together. @@ -507,7 +507,7 @@ proc `-`*(a: Duration): Duration {.operator.} = ## Reverse a duration. runnableExamples: doAssert -initDuration(seconds = 1) == initDuration(seconds = -1) - normalize[Duration](-a.seconds, -a.nanoseconds) + normalize[Duration](-a.seconds, -a.nanosecond) proc `<`*(a, b: Duration): bool {.operator.} = ## Note that a duration can be negative, @@ -530,7 +530,7 @@ proc `*`*(a: int64, b: Duration): Duration {.operator} = ## Multiply a duration by some scalar. runnableExamples: doAssert 5 * initDuration(seconds = 1) == initDuration(seconds = 5) - normalize[Duration](a * b.seconds, a * b.nanoseconds) + normalize[Duration](a * b.seconds, a * b.nanosecond) proc `*`*(a: Duration, b: int64): Duration {.operator} = ## Multiply a duration by some scalar. @@ -544,7 +544,7 @@ proc `div`*(a: Duration, b: int64): Duration {.operator} = doAssert initDuration(seconds = 3) div 2 == initDuration(milliseconds = 1500) doAssert initDuration(nanoseconds = 3) div 2 == initDuration(nanoseconds = 1) let carryOver = convert(Seconds, Nanoseconds, a.seconds mod b) - normalize[Duration](a.seconds div b, (a.nanoseconds + carryOver) div b) + normalize[Duration](a.seconds div b, (a.nanosecond + carryOver) div b) proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} = ## Computes the duration between two points in time. @@ -600,7 +600,7 @@ proc abs*(a: Duration): Duration = runnableExamples: doAssert initDuration(milliseconds = -1500).abs == initDuration(milliseconds = 1500) - initDuration(seconds = abs(a.seconds), nanoseconds = -a.nanoseconds) + initDuration(seconds = abs(a.seconds), nanoseconds = -a.nanosecond) proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} = ## Converts a broken-down time structure to @@ -650,7 +650,7 @@ proc initDateTime(zt: ZonedTime, zone: Timezone): DateTime = hour: hour, minute: minute, second: second, - nanosecond: zt.adjTime.nanoseconds, + nanosecond: zt.adjTime.nanosecond, weekday: getDayOfWeek(d, m, y), yearday: getDayOfYear(d, m, y), isDst: zt.isDst, @@ -809,7 +809,7 @@ else: # as a result of offset changes (normally due to dst) let utcUnix = adjTime.seconds + utcOffset let (finalOffset, dst) = getLocalOffsetAndDst(utcUnix) - result.adjTime = initTime(utcUnix - finalOffset, adjTime.nanoseconds) + result.adjTime = initTime(utcUnix - finalOffset, adjTime.nanosecond) result.utcOffset = finalOffset result.isDst = dst @@ -1806,7 +1806,7 @@ proc toSeconds*(time: Time): float {.tags: [], raises: [], benign, deprecated.} ## Returns the time in seconds since the unix epoch. ## ## **Deprecated since v0.18.0:** use ``fromUnix`` instead - time.seconds.float + time.nanoseconds / convert(Seconds, Nanoseconds, 1) + time.seconds.float + time.nanosecond / convert(Seconds, Nanoseconds, 1) proc getLocalTime*(time: Time): DateTime {.tags: [], raises: [], benign, deprecated.} = ## Converts the calendar time `time` to broken-time representation, @@ -1853,7 +1853,7 @@ when defined(JS): ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead. let dur = getTime() - start result = (convert(Seconds, Milliseconds, dur.seconds) + - convert(Nanoseconds, Milliseconds, dur.nanoseconds)).int + convert(Nanoseconds, Milliseconds, dur.nanosecond)).int else: proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} = when defined(macosx): diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 945d7ba3dc..37e14c1e2c 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -367,6 +367,10 @@ suite "ttimes": check d(seconds = 0) - d(milliseconds = 1500) == d(milliseconds = -1500) check d(milliseconds = -1500) == d(seconds = -1, milliseconds = -500) check d(seconds = -1, milliseconds = 500) == d(milliseconds = -500) + check initDuration(seconds = 1, nanoseconds = 2) <= + initDuration(seconds = 1, nanoseconds = 3) + check (initDuration(seconds = 1, nanoseconds = 3) <= + initDuration(seconds = 1, nanoseconds = 1)).not test "large/small dates": discard initDateTime(1, mJan, -35_000, 12, 00, 00, utc()) @@ -413,7 +417,7 @@ suite "ttimes": test "fromWinTime/toWinTime": check 0.fromUnix.toWinTime.fromWinTime.toUnix == 0 - check (-1).fromWinTime.nanoseconds == convert(Seconds, Nanoseconds, 1) - 100 + check (-1).fromWinTime.nanosecond == convert(Seconds, Nanoseconds, 1) - 100 check -1.fromWinTime.toWinTime == -1 # One nanosecond is discarded due to differences in time resolution - check initTime(0, 101).toWinTime.fromWinTime.nanoseconds == 100 \ No newline at end of file + check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100 \ No newline at end of file From e931f3b5a9643e0d7ac45b88b0bddb32dda4c540 Mon Sep 17 00:00:00 2001 From: genotrance Date: Wed, 25 Apr 2018 03:52:32 -0500 Subject: [PATCH 052/214] Fixes #802, #803 and #3775 - genscript issues (#7677) * Fixes #802, #803 and #3775 - genscript issues * Test case for genscript * Test script * Verify on Linux * Update categories.nim * Fix merge * Improve test framework * Windows fixes --- compiler/commands.nim | 1 + compiler/extccomp.nim | 3 ++- doc/advopt.txt | 3 ++- tests/flags/tgenscript.nim | 5 +++++ tests/testament/backend.nim | 2 +- tests/testament/categories.nim | 28 +++++++++++++++++++++++++--- tests/testament/htmlgen.nim | 2 +- tests/testament/tester.nim | 25 ++++++++++++++++++++----- 8 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 tests/flags/tgenscript.nim diff --git a/compiler/commands.nim b/compiler/commands.nim index 591bf8883d..06b487cf04 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -652,6 +652,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "genscript", "gendeps": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optGenScript) + incl(gGlobalOptions, optCompileOnly) of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info) of "lib": expectArg(switch, arg, pass, info) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index f9b18a3354..f8938e3af5 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -470,8 +470,9 @@ proc execExternalProgram*(cmd: string, msg = hintExecuting) = proc generateScript(projectFile: string, script: Rope) = let (dir, name, ext) = splitFile(projectFile) - writeRope(script, dir / addFileExt("compile_" & name, + writeRope(script, getNimcacheDir() / addFileExt("compile_" & name, platform.OS[targetOS].scriptExt)) + copyFile(libpath / "nimbase.h", getNimcacheDir() / "nimbase.h") proc getOptSpeed(c: TSystemCC): string = result = getConfigVar(c, ".options.speed") diff --git a/doc/advopt.txt b/doc/advopt.txt index 0d1578f78f..d4a4b49613 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -35,7 +35,8 @@ Advanced options: --noLinking compile Nim and generated files but do not link --noMain do not generate a main procedure --genScript generate a compile script (in the 'nimcache' - subdirectory named 'compile_$$project$$scriptext') + subdirectory named 'compile_$$project$$scriptext'), + implies --compileOnly --genDeps generate a '.deps' file containing the dependencies --os:SYMBOL set the target operating system (cross-compilation) --cpu:SYMBOL set the target processor (cross-compilation) diff --git a/tests/flags/tgenscript.nim b/tests/flags/tgenscript.nim new file mode 100644 index 0000000000..6a037b5d8f --- /dev/null +++ b/tests/flags/tgenscript.nim @@ -0,0 +1,5 @@ +discard """ + file: "tgenscript.nim" +""" + +echo "--genscript" diff --git a/tests/testament/backend.nim b/tests/testament/backend.nim index 4acef9ca4e..385f1171c1 100644 --- a/tests/testament/backend.nim +++ b/tests/testament/backend.nim @@ -13,7 +13,7 @@ type CommitId = distinct string proc `$`*(id: MachineId): string {.borrow.} -proc `$`(id: CommitId): string {.borrow.} +#proc `$`(id: CommitId): string {.borrow.} # not used var thisMachine: MachineId diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 2f91987598..84e536636a 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -63,6 +63,26 @@ proc compileRodFiles(r: var TResults, cat: Category, options: string) = test "gtkex1", true test "gtkex2" +# --------------------- flags tests ------------------------------------------- + +proc flagTests(r: var TResults, cat: Category, options: string) = + # --genscript + const filename = "tests"/"flags"/"tgenscript" + const genopts = " --genscript" + let nimcache = nimcacheDir(filename, genopts, targetC) + testSpec r, makeTest(filename, genopts, cat) + + when defined(windows): + testExec r, makeTest(filename, " cmd /c cd " & nimcache & + " && compile_tgenscript.bat", cat) + + when defined(linux): + testExec r, makeTest(filename, " sh -c \"cd " & nimcache & + " && sh compile_tgenscript.sh\"", cat) + + # Run + testExec r, makeTest(filename, " " & nimcache / "tgenscript", cat) + # --------------------- DLL generation tests ---------------------------------- proc safeCopyFile(src, dest: string) = @@ -323,7 +343,7 @@ var nimbleDir = getEnv("NIMBLE_DIR").string if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" let nimbleExe = findExe("nimble") - packageDir = nimbleDir / "pkgs" + #packageDir = nimbleDir / "pkgs" # not used packageIndex = nimbleDir / "packages.json" proc waitForExitEx(p: Process): int = @@ -407,9 +427,9 @@ proc `&.?`(a, b: string): string = # candidate for the stdlib? result = if b.startswith(a): b else: a & b -proc `&?.`(a, b: string): string = +#proc `&?.`(a, b: string): string = # not used # candidate for the stdlib? - result = if a.endswith(b): a else: a & b + #result = if a.endswith(b): a else: a & b proc processSingleTest(r: var TResults, cat: Category, options, test: string) = let test = "tests" & DirSep &.? cat.string / test @@ -429,6 +449,8 @@ proc processCategory(r: var TResults, cat: Category, options: string) = jsTests(r, cat, options) of "dll": dllTests(r, cat, options) + of "flags": + flagTests(r, cat, options) of "gc": gcTests(r, cat, options) of "longgc": diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim index bf26a956d2..4a888427e0 100644 --- a/tests/testament/htmlgen.nim +++ b/tests/testament/htmlgen.nim @@ -121,7 +121,7 @@ proc generateAllTestsContent(outfile: File, allResults: AllTests, proc generateHtml*(filename: string, onlyFailing: bool) = let - currentTime = getTime().getLocalTime() + currentTime = getTime().local() timestring = htmlQuote format(currentTime, "yyyy-MM-dd HH:mm:ss 'UTC'zzz") var outfile = open(filename, fmWrite) diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index 856f95f3b6..f08c830790 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -16,7 +16,7 @@ import const resultsFile = "testresults.html" - jsonFile = "testresults.json" + #jsonFile = "testresults.json" # not used Usage = """Usage: tester [options] command [arguments] @@ -150,11 +150,11 @@ proc initResults: TResults = result.skipped = 0 result.data = "" -proc readResults(filename: string): TResults = - result = marshal.to[TResults](readFile(filename).string) +#proc readResults(filename: string): TResults = # not used +# result = marshal.to[TResults](readFile(filename).string) -proc writeResults(filename: string, r: TResults) = - writeFile(filename, $$r) +#proc writeResults(filename: string, r: TResults) = # not used +# writeFile(filename, $$r) proc `$`(x: TResults): string = result = ("Tests passed: $1 / $3
\n" & @@ -404,6 +404,21 @@ proc testC(r: var TResults, test: TTest) = if exitCode != 0: given.err = reExitCodesDiffer if given.err == reSuccess: inc(r.passed) +proc testExec(r: var TResults, test: TTest) = + # runs executable or script, just goes by exit code + inc(r.total) + let (outp, errC) = execCmdEx(test.options.strip()) + var given: TSpec + specDefaults(given) + if errC == 0: + given.err = reSuccess + else: + given.err = reExitCodesDiffer + given.msg = outp.string + + if given.err == reSuccess: inc(r.passed) + r.addResult(test, targetC, "", given.msg, given.err) + proc makeTest(test, options: string, cat: Category, action = actionCompile, env: string = ""): TTest = # start with 'actionCompile', will be overwritten in the spec: From e1cd4bca0e74e394f75eb68c6c14ebc54205c369 Mon Sep 17 00:00:00 2001 From: Terence Namusonge Date: Wed, 25 Apr 2018 14:30:54 +0200 Subject: [PATCH 053/214] tiny typo --- lib/pure/json.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 6740f483d5..d2845795c1 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -721,7 +721,7 @@ proc getBool*(n: JsonNode, default: bool = false): bool = else: return n.bval proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated.} = - ## Deprecated - use getBVal instead + ## Deprecated - use getBool instead getBool(n, default) proc getFields*(n: JsonNode, From be8ce30acdd9d0cfad2cce605e1d738537dd7c12 Mon Sep 17 00:00:00 2001 From: David Krause Date: Wed, 25 Apr 2018 16:06:53 +0200 Subject: [PATCH 054/214] copy pastable progress reporting example --- lib/pure/httpclient.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 70fb194341..0aa75dcfbd 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -73,12 +73,13 @@ ## progress of the HTTP request. ## ## .. code-block:: Nim +## import asyncdispatch, httpclient ## var client = newAsyncHttpClient() ## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} = ## echo("Downloaded ", progress, " of ", total) ## echo("Current rate: ", speed div 1000, "kb/s") ## client.onProgressChanged = onProgressChanged -## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") +## discard waitFor client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") ## ## If you would like to remove the callback simply set it to ``nil``. ## From d01b1558a3573a07372103b09037992b5380903d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 25 Apr 2018 22:49:29 +0100 Subject: [PATCH 055/214] Improve progress reporting example. Refs #7693 --- lib/pure/httpclient.nim | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 0aa75dcfbd..27ae93e530 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -74,12 +74,17 @@ ## ## .. code-block:: Nim ## import asyncdispatch, httpclient -## var client = newAsyncHttpClient() +## ## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} = ## echo("Downloaded ", progress, " of ", total) ## echo("Current rate: ", speed div 1000, "kb/s") -## client.onProgressChanged = onProgressChanged -## discard waitFor client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") +## +## proc asyncProc() {.async.} = +## var client = newAsyncHttpClient() +## client.onProgressChanged = onProgressChanged +## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") +## +## waitFor asyncProc() ## ## If you would like to remove the callback simply set it to ``nil``. ## From aa48a472fd92a6ced75780fd26193212e715b0f9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 25 Apr 2018 22:56:51 +0100 Subject: [PATCH 056/214] Improve deprecation messages in json docs. --- lib/pure/json.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index d2845795c1..574b13fbf2 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -696,7 +696,7 @@ proc getBiggestInt*(n: JsonNode, default: BiggestInt = 0): BiggestInt = else: return n.num proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated.} = - ## Deprecated - use getInt or getBiggestInt instead + ## **Deprecated since v0.18.2:** use ``getInt`` or ``getBiggestInt`` instead. getBiggestInt(n, default) proc getFloat*(n: JsonNode, default: float = 0.0): float = @@ -710,7 +710,7 @@ proc getFloat*(n: JsonNode, default: float = 0.0): float = else: return default proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated.} = - ## Deprecated - use getFloat instead + ## **Deprecated since v0.18.2:** use ``getFloat`` instead. getFloat(n, default) proc getBool*(n: JsonNode, default: bool = false): bool = @@ -721,7 +721,7 @@ proc getBool*(n: JsonNode, default: bool = false): bool = else: return n.bval proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated.} = - ## Deprecated - use getBool instead + ## **Deprecated since v0.18.2:** use ``getBool`` instead. getBool(n, default) proc getFields*(n: JsonNode, @@ -947,7 +947,7 @@ proc contains*(node: JsonNode, val: JsonNode): bool = find(node.elems, val) >= 0 proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key) - ## Deprecated for `hasKey` + ## **Deprecated:** use `hasKey` instead. proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} = ## Sets a field from a `JObject`. From 397e1731393be598991df302006ec3634baa3583 Mon Sep 17 00:00:00 2001 From: hlaaf Date: Thu, 26 Apr 2018 20:54:14 +0300 Subject: [PATCH 057/214] fix #7680 (#7683) * fix #7680 * Don't send on every HTTP method * These should be squashed * 80 column limit --- lib/pure/httpclient.nim | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 27ae93e530..db8acf0eb4 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -745,10 +745,11 @@ proc downloadFile*(url: string, outputFilename: string, proc generateHeaders(requestUrl: Uri, httpMethod: string, headers: HttpHeaders, body: string, proxy: Proxy): string = # GET - result = httpMethod.toUpperAscii() + let upperMethod = httpMethod.toUpperAscii() + result = upperMethod result.add ' ' - if proxy.isNil or (not proxy.isNil and requestUrl.scheme == "https"): + if proxy.isNil or requestUrl.scheme == "https": # /path?query if requestUrl.path[0] != '/': result.add '/' result.add(requestUrl.path) @@ -774,7 +775,9 @@ proc generateHeaders(requestUrl: Uri, httpMethod: string, add(result, "Connection: Keep-Alive\c\L") # Content length header. - if body.len > 0 and not headers.hasKey("Content-Length"): + const requiresBody = ["POST", "PUT", "PATCH"] + let needsContentLength = body.len > 0 or upperMethod in requiresBody + if needsContentLength and not headers.hasKey("Content-Length"): add(result, "Content-Length: " & $body.len & "\c\L") # Proxy auth header. From d4867cbcbd1325c627612fbb4ff331394cd2c2a3 Mon Sep 17 00:00:00 2001 From: SolitudeSF Date: Thu, 26 Apr 2018 23:08:57 +0300 Subject: [PATCH 058/214] link against libssl.so.45 --- lib/wrappers/openssl.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 86ae853696..6609dc2452 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -38,7 +38,7 @@ when useWinVersion: from winlean import SocketHandle else: - const versions = "(.1.1|.38|.39|.41|.43|.44|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)" + const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)" when defined(macosx): const From e4aa140d22fe065bee78a1edaadbd5bae3160779 Mon Sep 17 00:00:00 2001 From: andri lim Date: Fri, 27 Apr 2018 13:53:20 +0700 Subject: [PATCH 059/214] fixes #7600, generic object with generic ref object parent typerel bug (#7678) * fixes #7600 * fix wrong logic --- compiler/sigmatch.nim | 9 +++++++-- tests/typerel/t7600_1.nim | 18 ++++++++++++++++++ tests/typerel/t7600_2.nim | 17 +++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 tests/typerel/t7600_1.nim create mode 100644 tests/typerel/t7600_2.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 96d815df72..552d2cdca7 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1388,8 +1388,13 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, var aAsObject = roota.lastSon - if fKind in {tyRef, tyPtr} and aAsObject.kind == fKind: - aAsObject = aAsObject.base + if fKind in {tyRef, tyPtr}: + if aAsObject.kind == tyObject: + # bug #7600, tyObject cannot be passed + # as argument to tyRef/tyPtr + return isNone + elif aAsObject.kind == fKind: + aAsObject = aAsObject.base if aAsObject.kind == tyObject: let baseType = aAsObject.base diff --git a/tests/typerel/t7600_1.nim b/tests/typerel/t7600_1.nim new file mode 100644 index 0000000000..e3a5fefa2c --- /dev/null +++ b/tests/typerel/t7600_1.nim @@ -0,0 +1,18 @@ +discard """ +errormsg: "type mismatch: got " +nimout: '''t7600_1.nim(18, 6) Error: type mismatch: got +but expected one of: +proc test[T](x: Paper[T]) + +expression: test tn''' +""" + +type + Paper[T] = ref object of RootObj + thickness: T + Thin[T] = object of Paper[T] + +proc test[T](x: Paper[T]) = discard + +var tn = Thin[int]() +test tn diff --git a/tests/typerel/t7600_2.nim b/tests/typerel/t7600_2.nim new file mode 100644 index 0000000000..7badb69cfb --- /dev/null +++ b/tests/typerel/t7600_2.nim @@ -0,0 +1,17 @@ +discard """ +errormsg: "type mismatch: got " +nimout: '''t7600_2.nim(17, 6) Error: type mismatch: got +but expected one of: +proc test(x: Paper) + +expression: test tn''' +""" + +type + Paper = ref object of RootObj + Thin = object of Paper + +proc test(x: Paper) = discard + +var tn = Thin() +test tn From e50f69bc87e77922bf33310b8fbdcbaf9664a48e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 24 Apr 2018 20:12:13 +0200 Subject: [PATCH 060/214] nimgrep: count the number of matches --- tools/nimgrep.nim | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 4cfcbe9bc2..9cfd7a86f6 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -128,7 +128,7 @@ proc highlight(s, match, repl: string, t: tuple[first, last: int], stdout.write("\n") stdout.flushFile() -proc processFile(pattern; filename: string) = +proc processFile(pattern; filename: string; counter: var int) = var filenameShown = false template beforeHighlight = if not filenameShown and optVerbose notin options and not oneline: @@ -166,6 +166,7 @@ proc processFile(pattern; filename: string) = var wholeMatch = buffer.substr(t.first, t.last) beforeHighlight() + inc counter if optReplace notin options: highlight(buffer, wholeMatch, "", t, filename, line, showRepl=false) else: @@ -241,17 +242,17 @@ proc styleInsensitive(s: string): string = addx() else: addx() -proc walker(pattern; dir: string) = +proc walker(pattern; dir: string; counter: var int) = for kind, path in walkDir(dir): case kind of pcFile: if extensions.len == 0 or path.hasRightExt(extensions): - processFile(pattern, path) + processFile(pattern, path, counter) of pcDir: if optRecursive in options: - walker(pattern, path) + walker(pattern, path, counter) else: discard - if existsFile(dir): processFile(pattern, dir) + if existsFile(dir): processFile(pattern, dir, counter) proc writeHelp() = stdout.write(Usage) @@ -321,6 +322,7 @@ if optStdin in options: if pattern.len == 0: writeHelp() else: + var counter = 0 if filenames.len == 0: filenames.add(os.getCurrentDir()) if optRegex notin options: @@ -332,7 +334,7 @@ else: pattern = "\\i " & pattern let pegp = peg(pattern) for f in items(filenames): - walker(pegp, f) + walker(pegp, f, counter) else: var reflags = {reStudy, reExtended} if optIgnoreStyle in options: @@ -343,5 +345,6 @@ else: reflags.incl reIgnoreCase let rep = re(pattern, reflags) for f in items(filenames): - walker(rep, f) - + walker(rep, f, counter) + if not oneline: + stdout.write($counter & " matches\n") From c71c951a64c8c0adc6f6ae9992bc8bfeb003a31f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 26 Apr 2018 15:41:33 +0200 Subject: [PATCH 061/214] enforce dot and call operators are used with an explicit .experimental pragma --- compiler/semstmts.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 94090852f8..aaf14fb893 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1588,9 +1588,11 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) if s.name.s[0] in {'.', '('}: if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}: - message(n.info, warnDeprecated, "overloaded '.' and '()' operators are now .experimental; " & s.name.s) + localError(n.info, "the overloaded " & s.name.s & + " operator has to be enabled with {.experimental: \"dotOperators\".}") elif s.name.s == "()" and callOperator notin c.features: - message(n.info, warnDeprecated, "overloaded '()' operators are now .experimental; " & s.name.s) + localError(n.info, "the overloaded " & s.name.s & + " operator has to be enabled with {.experimental: \"callOperator\".}") if n.sons[bodyPos].kind != nkEmpty: # for DLL generation it is annoying to check for sfImportc! From ef1b547f358ce610e8f728a05169a2ee434b8f87 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 27 Apr 2018 09:57:14 +0200 Subject: [PATCH 062/214] 'add' on a nil sequence doesn't produce a crash anymore --- compiler/ccgexprs.nim | 8 ++++---- lib/system/sysstr.nim | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index ea373f5a6a..ef21743d89 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1086,17 +1086,17 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; let seqAppendPattern = if not p.module.compileToCpp: - "$1 = ($2) #incrSeqV2(&($1)->Sup, sizeof($3));$n" + "$1 = ($2) #incrSeqV3(&($1)->Sup, $3);$n" else: - "$1 = ($2) #incrSeqV2($1, sizeof($3));$n" + "$1 = ($2) #incrSeqV3($1, $3);$n" var a, b, dest, tmpL: TLoc initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) - let bt = skipTypes(e.sons[2].typ, {tyVar}) + let seqType = skipTypes(e.sons[1].typ, {tyVar}) lineCg(p, cpsStmts, seqAppendPattern, [ rdLoc(a), getTypeDesc(p.module, e.sons[1].typ), - getTypeDesc(p.module, bt)]) + genTypeInfo(p.module, seqType, e.info)]) #if bt != b.t: # echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t) initLoc(dest, locExpr, e.sons[2], OnHeap) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index ea0273340d..7640b888ba 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -261,6 +261,18 @@ proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} = GenericSeqSize)) result.reserved = r +proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} = + if s == nil: + result = cast[PGenericSeq](newSeq(typ, 1)) + result.len = 0 + else: + result = s + if result.len >= result.space: + let r = resize(result.space) + result = cast[PGenericSeq](growObj(result, typ.base.size * r + + GenericSeqSize)) + result.reserved = r + proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. compilerRtl, inl.} = result = seq From ce36b8efd6795500694e954979e1ccb97058583d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 27 Apr 2018 11:07:40 +0200 Subject: [PATCH 063/214] setLen doesn't crash on nil strings/seqs anymore --- compiler/ccgexprs.nim | 6 +++--- lib/system/sysstr.nim | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index ef21743d89..7040b75c62 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1500,13 +1500,13 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[2], b) let t = skipTypes(e.sons[1].typ, {tyVar}) let setLenPattern = if not p.module.compileToCpp: - "$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n" + "$1 = ($3) #setLengthSeqV2(&($1)->Sup, $4, $2);$n" else: - "$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n" + "$1 = ($3) #setLengthSeqV2($1, $4, $2);$n" lineCg(p, cpsStmts, setLenPattern, [ rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), - getTypeDesc(p.module, t.skipTypes(abstractInst).sons[0])]) + genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) gcUsage(e) proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 7640b888ba..42aae66549 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -226,8 +226,8 @@ proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} = proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} = var n = max(newLen, 0) - if wasMoved(s): - result = newOwnedString(s, n) + if s == nil: + result = mnewString(newLen) elif n <= s.space: result = s else: @@ -313,6 +313,13 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. (newLen*%elemSize)), (result.len-%newLen) *% elemSize) result.len = newLen +proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. + compilerRtl.} = + if s == nil: + result = cast[PGenericSeq](newSeq(typ, newLen)) + else: + result = setLengthSeq(s, typ.base.size, newLen) + # --------------- other string routines ---------------------------------- proc add*(result: var string; x: int64) = let base = result.len From c8a412998a5ca16a7f96c6f6d41061d976aa13b4 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sat, 28 Apr 2018 01:58:39 +0700 Subject: [PATCH 064/214] make nimfix compile again (#7708) --- compiler/nimfix/nimfix.nim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim index a97d88078e..2ef375b002 100644 --- a/compiler/nimfix/nimfix.nim +++ b/compiler/nimfix/nimfix.nim @@ -47,7 +47,7 @@ proc mainCommand = compileProject(newModuleGraph(), newIdentCache()) pretty.overwriteFiles() -proc processCmdLine*(pass: TCmdLinePass, cmd: string) = +proc processCmdLine*(pass: TCmdLinePass, cmd: string, config: ConfigRef) = var p = parseopt.initOptParser(cmd) var argsCount = 0 gOnlyMainfile = true @@ -76,16 +76,16 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = of "wholeproject": gOnlyMainfile = false of "besteffort": msgs.gErrorMax = high(int) # don't stop after first error else: - processSwitch(pass, p) + processSwitch(pass, p, config) of cmdArgument: options.gProjectName = unixToNativePath(p.key) # if processArgument(pass, p, argsCount): break -proc handleCmdLine() = +proc handleCmdLine(config: ConfigRef) = if paramCount() == 0: stdout.writeLine(Usage) else: - processCmdLine(passCmd1, "") + processCmdLine(passCmd1, "", config) if gProjectName != "": try: gProjectFull = canonicalizePath(gProjectName) @@ -96,11 +96,11 @@ proc handleCmdLine() = gProjectName = p.name else: gProjectPath = getCurrentDir() - loadConfigs(DefaultConfig) # load all config files + loadConfigs(DefaultConfig, config) # load all config files # now process command line arguments again, because some options in the # command line can overwite the config file's settings extccomp.initVars() - processCmdLine(passCmd2, "") + processCmdLine(passCmd2, "", config) mainCommand() when compileOption("gc", "v2") or compileOption("gc", "refc"): @@ -108,4 +108,4 @@ when compileOption("gc", "v2") or compileOption("gc", "refc"): condsyms.initDefines() defineSymbol "nimfix" -handleCmdline() +handleCmdline newConfigRef() From 7c538b26ad03b077da84766771b85d72d978b598 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 27 Apr 2018 21:32:58 +0200 Subject: [PATCH 065/214] nil in string concats does not produce crashes anymore --- compiler/ccgexprs.nim | 2 +- lib/system/sysstr.nim | 27 ++++++++++++++++----------- tests/system/tnilconcats.nim | 25 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 tests/system/tnilconcats.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 7040b75c62..a2789138b7 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1034,7 +1034,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: - addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)]) + addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a))) linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L)) add(p.s(cpsStmts), appends) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 42aae66549..e64e12fc7f 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -161,14 +161,16 @@ proc hashString(s: string): int {.compilerproc.} = proc addChar(s: NimString, c: char): NimString = # is compilerproc! - result = s - if result.len >= result.space: - let r = resize(result.space) - result = cast[NimString](growObj(result, - sizeof(TGenericSeq) + r + 1)) - result.reserved = r - elif wasMoved(s): - result = newOwnedString(s, s.len) + if s == nil: + result = rawNewStringNoInit(1) + result.len = 0 + else: + result = s + if result.len >= result.space: + let r = resize(result.space) + result = cast[NimString](growObj(result, + sizeof(TGenericSeq) + r + 1)) + result.reserved = r result.data[result.len] = c result.data[result.len+1] = '\0' inc(result.len) @@ -205,7 +207,9 @@ proc addChar(s: NimString, c: char): NimString = # s = rawNewString(0); proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} = - if dest.len + addlen <= dest.space and not wasMoved(dest): + if dest == nil: + result = rawNewStringNoInit(addlen) + elif dest.len + addlen <= dest.space and not wasMoved(dest): result = dest else: # slow path: var sp = max(resize(dest.space), dest.len + addlen) @@ -216,8 +220,9 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} = # DO NOT UPDATE LEN YET: dest.len = newLen proc appendString(dest, src: NimString) {.compilerproc, inline.} = - copyMem(addr(dest.data[dest.len]), addr(src.data), src.len + 1) - inc(dest.len, src.len) + if src != nil: + copyMem(addr(dest.data[dest.len]), addr(src.data), src.len + 1) + inc(dest.len, src.len) proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} = dest.data[dest.len] = c diff --git a/tests/system/tnilconcats.nim b/tests/system/tnilconcats.nim new file mode 100644 index 0000000000..ce059b7b0e --- /dev/null +++ b/tests/system/tnilconcats.nim @@ -0,0 +1,25 @@ +discard """ + output: '''@[nil, nil, nil, nil, nil, nil, nil, "meh"]''' + exitcode: "0" +""" + +when true: + var ab: string + ab &= "more" + + doAssert ab == "more" + + var x: seq[string] + + setLen(x, 7) + + x.add "meh" + + var s: string + var z = "abc" + var zz: string + s &= "foo" & z & zz + + doAssert s == "fooabc" + + echo x From 822d2b5085f503a1802dd2c77d6348ffe53e4d37 Mon Sep 17 00:00:00 2001 From: Varriount Date: Fri, 27 Apr 2018 15:35:41 -0400 Subject: [PATCH 066/214] Fix the return value of GetType and friends when given a `var T` type. (#7701) --- compiler/vmdeps.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 071cc7706e..ba37237e82 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -208,7 +208,12 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; result.add mapTypeToAst(t.sons[0], info) else: result = mapTypeToBracket("ref", mRef, t, info) - of tyVar: result = mapTypeToBracket("var", mVar, t, info) + of tyVar: + if inst: + result = newNodeX(nkVarTy) + result.add mapTypeToAst(t.sons[0], info) + else: + result = mapTypeToBracket("var", mVar, t, info) of tyLent: result = mapTypeToBracket("lent", mBuiltinType, t, info) of tySink: result = mapTypeToBracket("sink", mBuiltinType, t, info) of tySequence: result = mapTypeToBracket("seq", mSeq, t, info) From 07d6ff4be4941cdefd71fce35cd304d7b3f1c805 Mon Sep 17 00:00:00 2001 From: andri lim Date: Sat, 28 Apr 2018 02:38:15 +0700 Subject: [PATCH 067/214] fixes #7601, array construction of ptr generics (#7671) * fixes #7601, array construction of ptr generics * add more test --- compiler/sem.nim | 5 ++- tests/array/tarraycons_ptr_generic.nim | 51 +++++++++++++++++++++++++ tests/array/tarraycons_ptr_generic2.nim | 17 +++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 tests/array/tarraycons_ptr_generic.nim create mode 100644 tests/array/tarraycons_ptr_generic2.nim diff --git a/compiler/sem.nim b/compiler/sem.nim index 041f2e1274..52282d0e49 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -153,8 +153,9 @@ proc commonType*(x, y: PType): PType = if a.kind in {tyRef, tyPtr}: k = a.kind if b.kind != a.kind: return x - a = a.lastSon - b = b.lastSon + # bug #7601, array construction of ptr generic + a = a.lastSon.skipTypes({tyGenericInst}) + b = b.lastSon.skipTypes({tyGenericInst}) if a.kind == tyObject and b.kind == tyObject: result = commonSuperclass(a, b) # this will trigger an error later: diff --git a/tests/array/tarraycons_ptr_generic.nim b/tests/array/tarraycons_ptr_generic.nim new file mode 100644 index 0000000000..eb89a196fc --- /dev/null +++ b/tests/array/tarraycons_ptr_generic.nim @@ -0,0 +1,51 @@ +discard """ + output: '''apple +banana +Fruit +2 +4 +3 +none +skin +paper +''' +""" +type + Fruit = object of RootObj + name: string + Apple = object of Fruit + Banana = object of Fruit + +var + ir = Fruit(name: "Fruit") + ia = Apple(name: "apple") + ib = Banana(name: "banana") + +let x = [ia.addr, ib.addr, ir.addr] +for c in x: echo c.name + +type + Vehicle[T] = object of RootObj + tire: T + Car[T] = object of Vehicle[T] + Bike[T] = object of Vehicle[T] + +var v = Vehicle[int](tire: 3) +var c = Car[int](tire: 4) +var b = Bike[int](tire: 2) + +let y = [b.addr, c.addr, v.addr] +for c in y: echo c.tire + +type + Book[T] = ref object of RootObj + cover: T + Hard[T] = ref object of Book[T] + Soft[T] = ref object of Book[T] + +var bn = Book[string](cover: "none") +var hs = Hard[string](cover: "skin") +var bp = Soft[string](cover: "paper") + +let z = [bn, hs, bp] +for c in z: echo c.cover diff --git a/tests/array/tarraycons_ptr_generic2.nim b/tests/array/tarraycons_ptr_generic2.nim new file mode 100644 index 0000000000..fce7af6691 --- /dev/null +++ b/tests/array/tarraycons_ptr_generic2.nim @@ -0,0 +1,17 @@ +discard """ + file: "tarraycons_ptr_generic2.nim" + line: 17 + errormsg: "type mismatch: got but expected 'Book[system.string]'" +""" + +type + Book[T] = ref object of RootObj + cover: T + Hard[T] = ref object of Book[T] + Soft[T] = ref object of Book[T] + +var bn = Book[string](cover: "none") +var hs = Hard[string](cover: "skin") +var bp = Soft[string](cover: "paper") + +let z = [bn, hs.addr, bp] From f755808350f7dfe713f68e0e7f50b7be989841ab Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 00:00:19 +0200 Subject: [PATCH 068/214] remove standalone 'except' and 'finally' statements that have been deprecated for years --- compiler/semstmts.nim | 110 +++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 72 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index aaf14fb893..4ee8f12644 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1843,80 +1843,46 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = # nkNilLit, nkEmpty}: # dec last for i in countup(0, length - 1): - let k = n.sons[i].kind - case k - of nkFinally, nkExceptBranch: - # stand-alone finally and except blocks are - # transformed into regular try blocks: - # - # var f = fopen("somefile") | var f = fopen("somefile") - # finally: fclose(f) | try: - # ... | ... - # | finally: - # | fclose(f) - var deferPart: PNode - if k == nkDefer: - deferPart = newNodeI(nkFinally, n.sons[i].info) - deferPart.add n.sons[i].sons[0] - elif k == nkFinally: - message(n.info, warnDeprecated, - "use 'defer'; standalone 'finally'") - deferPart = n.sons[i] - else: - message(n.info, warnDeprecated, - "use an explicit 'try'; standalone 'except'") - deferPart = n.sons[i] - var tryStmt = newNodeI(nkTryStmt, n.sons[i].info) - var body = newNodeI(nkStmtList, n.sons[i].info) - if i < n.sonsLen - 1: - body.sons = n.sons[(i+1)..n.len-1] - tryStmt.addSon(body) - tryStmt.addSon(deferPart) - n.sons[i] = semTry(c, tryStmt) - n.sons.setLen(i+1) - n.typ = n.sons[i].typ - return - else: - var expr = semExpr(c, n.sons[i], flags) - n.sons[i] = expr - if c.matchedConcept != nil and expr.typ != nil and - (nfFromTemplate notin n.flags or i != last): - case expr.typ.kind - of tyBool: - if expr.kind == nkInfix and - expr[0].kind == nkSym and - expr[0].sym.name.s == "==": - if expr[1].typ.isUnresolvedStatic: - inferConceptStaticParam(c, expr[1], expr[2]) - continue - elif expr[2].typ.isUnresolvedStatic: - inferConceptStaticParam(c, expr[2], expr[1]) - continue + var expr = semExpr(c, n.sons[i], flags) + n.sons[i] = expr + if c.matchedConcept != nil and expr.typ != nil and + (nfFromTemplate notin n.flags or i != last): + case expr.typ.kind + of tyBool: + if expr.kind == nkInfix and + expr[0].kind == nkSym and + expr[0].sym.name.s == "==": + if expr[1].typ.isUnresolvedStatic: + inferConceptStaticParam(c, expr[1], expr[2]) + continue + elif expr[2].typ.isUnresolvedStatic: + inferConceptStaticParam(c, expr[2], expr[1]) + continue - let verdict = semConstExpr(c, n[i]) - if verdict.intVal == 0: - localError(result.info, "concept predicate failed") - of tyUnknown: continue - else: discard - if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]): - voidContext = true - n.typ = enforceVoidContext - if i == last and (length == 1 or efWantValue in flags): - n.typ = n.sons[i].typ - if not isEmptyType(n.typ): n.kind = nkStmtListExpr - elif i != last or voidContext: - discardCheck(c, n.sons[i]) - else: - n.typ = n.sons[i].typ - if not isEmptyType(n.typ): n.kind = nkStmtListExpr - if n.sons[i].kind in LastBlockStmts or - n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and sfNoReturn in n.sons[i][0].sym.flags: - for j in countup(i + 1, length - 1): - case n.sons[j].kind - of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr, - nkBlockStmt, nkState: discard - else: localError(n.sons[j].info, errStmtInvalidAfterReturn) + let verdict = semConstExpr(c, n[i]) + if verdict.intVal == 0: + localError(result.info, "concept predicate failed") + of tyUnknown: continue else: discard + if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]): + voidContext = true + n.typ = enforceVoidContext + if i == last and (length == 1 or efWantValue in flags): + n.typ = n.sons[i].typ + if not isEmptyType(n.typ): n.kind = nkStmtListExpr + elif i != last or voidContext: + discardCheck(c, n.sons[i]) + else: + n.typ = n.sons[i].typ + if not isEmptyType(n.typ): n.kind = nkStmtListExpr + if n.sons[i].kind in LastBlockStmts or + n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and sfNoReturn in n.sons[i][0].sym.flags: + for j in countup(i + 1, length - 1): + case n.sons[j].kind + of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr, + nkBlockStmt, nkState: discard + else: localError(n.sons[j].info, errStmtInvalidAfterReturn) + else: discard if result.len == 1 and # concept bodies should be preserved as a stmt list: From f697596faf1712753efb14220b8991566bd7267f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 07:49:36 +0200 Subject: [PATCH 069/214] semcheck: code cleanups --- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 6 +---- compiler/semstmts.nim | 52 +++---------------------------------------- 3 files changed, 5 insertions(+), 55 deletions(-) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 8159abf8f9..fc0488814c 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -63,7 +63,7 @@ type # to the user. efWantStmt, efAllowStmt, efDetermineType, efExplain, efAllowDestructor, efWantValue, efOperand, efNoSemCheck, - efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo, + efNoEvaluateGeneric, efInCall, efFromHlo TExprFlags* = set[TExprFlag] diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 6ad5d931d4..22dee81b71 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -51,7 +51,6 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = renderTree(result, {renderNoComments})) result.typ = errorType(c) else: - if efNoProcvarCheck notin flags: semProcvarCheck(c, result) if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = @@ -63,8 +62,6 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = localError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) result.typ = errorType(c) - else: - semProcvarCheck(c, result) proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = symChoice(c, n, s, scClosed) @@ -540,7 +537,6 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = # we need to recurse explicitly here as converters can create nested # calls and then they wouldn't be analysed otherwise analyseIfAddressTakenInCall(c, n.sons[i]) - semProcvarCheck(c, n.sons[i]) if i < sonsLen(t) and skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar: if n.sons[i].kind != nkHiddenAddr: @@ -1245,7 +1241,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = checkMinSonsLen(n, 2) # make sure we don't evaluate generic macros/templates n.sons[0] = semExprWithType(c, n.sons[0], - {efNoProcvarCheck, efNoEvaluateGeneric}) + {efNoEvaluateGeneric}) let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink}) case arr.kind diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4ee8f12644..9ec04f35b5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -71,37 +71,12 @@ proc toCover(t: PType): BiggestInt = else: result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc})) -when false: - proc performProcvarCheck(c: PContext, info: TLineInfo, s: PSym) = - ## Checks that the given symbol is a proper procedure variable, meaning - ## that it - var smoduleId = getModule(s).id - if sfProcvar notin s.flags and s.typ.callConv == ccDefault and - smoduleId != c.module.id: - block outer: - for module in c.friendModules: - if smoduleId == module.id: - break outer - localError(info, errXCannotBePassedToProcVar, s.name.s) - -template semProcvarCheck(c: PContext, n: PNode) = - when false: - var n = n.skipConv - if n.kind in nkSymChoices: - for x in n: - if x.sym.kind in {skProc, skMethod, skConverter, skIterator}: - performProcvarCheck(c, n.info, x.sym) - elif n.kind == nkSym and n.sym.kind in {skProc, skMethod, skConverter, - skIterator}: - performProcvarCheck(c, n.info, n.sym) - proc semProc(c: PContext, n: PNode): PNode proc semExprBranch(c: PContext, n: PNode): PNode = result = semExpr(c, n) if result.typ != nil: # XXX tyGenericInst here? - semProcvarCheck(c, result) if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) proc semExprBranchScope(c: PContext, n: PNode): PNode = @@ -384,7 +359,7 @@ proc checkNilable(v: PSym) = include semasgn -proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) = +proc addToVarSection(c: PContext; result: PNode; orig, identDefs: PNode) = let L = identDefs.len let value = identDefs[L-1] if result.kind == nkStmtList: @@ -1684,11 +1659,6 @@ proc semIterator(c: PContext, n: PNode): PNode = incl(s.typ.flags, tfCapturesEnv) else: s.typ.callConv = ccInline - when false: - if s.typ.callConv != ccInline: - s.typ.callConv = ccClosure - # and they always at least use the 'env' for the state field: - incl(s.typ.flags, tfCapturesEnv) if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone: localError(n.info, errImplOfXexpected, s.name.s) @@ -1794,14 +1764,6 @@ proc semStaticStmt(c: PContext, n: PNode): PNode = evalStaticStmt(c.module, c.cache, a, c.p.owner) result = newNodeI(nkDiscardStmt, n.info, 1) result.sons[0] = emptyNode - when false: - result = evalStaticStmt(c.module, a, c.p.owner) - if result.isNil: - LocalError(n.info, errCannotInterpretNodeX, renderTree(n)) - result = emptyNode - elif result.kind == nkEmpty: - result = newNodeI(nkDiscardStmt, n.info, 1) - result.sons[0] = emptyNode proc usesResult(n: PNode): bool = # nkStmtList(expr) properly propagates the void context, @@ -1876,7 +1838,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = n.typ = n.sons[i].typ if not isEmptyType(n.typ): n.kind = nkStmtListExpr if n.sons[i].kind in LastBlockStmts or - n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and sfNoReturn in n.sons[i][0].sym.flags: + n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and + sfNoReturn in n.sons[i][0].sym.flags: for j in countup(i + 1, length - 1): case n.sons[j].kind of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr, @@ -1898,15 +1861,6 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = 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: - var lastStmt = lastSon(result) - if lastStmt.kind != nkNilLit and not implicitlyDiscardable(lastStmt): - result.typ = lastStmt.typ - #localError(lastStmt.info, errGenerated, - # "Last expression must be explicitly returned if it " & - # "is discardable or discarded") proc semStmt(c: PContext, n: PNode): PNode = # now: simply an alias: From 65c08212db7d2e8f778b0db43e831f5f3e86b8ce Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 07:57:44 +0200 Subject: [PATCH 070/214] system.nim: minor code cleanup --- lib/system/sysstr.nim | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index e64e12fc7f..9e7ee903f3 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -101,9 +101,6 @@ proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} = if str == nil: NimString(nil) else: toNimStr(str, str.len) -template wasMoved(x: NimString): bool = false -# (x.reserved and seqShallowFlag) != 0 - proc copyString(src: NimString): NimString {.compilerRtl.} = if src != nil: if (src.reserved and seqShallowFlag) != 0: @@ -209,7 +206,7 @@ proc addChar(s: NimString, c: char): NimString = proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} = if dest == nil: result = rawNewStringNoInit(addlen) - elif dest.len + addlen <= dest.space and not wasMoved(dest): + elif dest.len + addlen <= dest.space: result = dest else: # slow path: var sp = max(resize(dest.space), dest.len + addlen) From ee7515e376da88df2261fdb014ee5075919a7012 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 09:26:15 +0200 Subject: [PATCH 071/214] fixes #7663 --- compiler/semstmts.nim | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 9ec04f35b5..eafc9ee667 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -500,12 +500,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = localError(a.info, errXExpected, "tuple") elif length-2 != sonsLen(tup): localError(a.info, errWrongNumberOfVariables) - else: - b = newNodeI(nkVarTuple, a.info) - newSons(b, length) - b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator - b.sons[length-1] = def - addToVarSection(c, result, n, b) + b = newNodeI(nkVarTuple, a.info) + newSons(b, length) + b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator + b.sons[length-1] = def + addToVarSection(c, result, n, b) elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and a.kind == nkIdentDefs and a.len > 3: message(a.info, warnEachIdentIsTuple) @@ -547,7 +546,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = addToVarSection(c, result, n, b) else: if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j] - setVarType(v, tup.sons[j]) + # bug #7663, for 'nim check' this can be a non-tuple: + if tup.kind == tyTuple: setVarType(v, tup.sons[j]) + else: v.typ = tup b.sons[j] = newSymNode(v) checkNilable(v) if sfCompileTime in v.flags: hasCompileTime = true From 1eaeb8945b880ee90482bc399e2dbb320a98cd93 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 09:31:22 +0200 Subject: [PATCH 072/214] system.nim documentation: setLen can handle nil now --- lib/system.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 98c1334281..523a25d641 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1280,15 +1280,13 @@ proc setLen*[T](s: var seq[T], newlen: Natural) {. ## sets the length of `s` to `newlen`. ## ``T`` may be any sequence type. ## If the current length is greater than the new length, - ## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with - ## a size, use ``newSeq`` instead. + ## ``s`` will be truncated. proc setLen*(s: var string, newlen: Natural) {. magic: "SetLengthStr", noSideEffect.} ## sets the length of `s` to `newlen`. ## If the current length is greater than the new length, - ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with - ## a size, use ``newString`` instead. + ## ``s`` will be truncated. ## ## .. code-block:: Nim ## var myS = "Nim is great!!" From e3379770b2f7107a3cf04375af5e677c793972bc Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 09:56:10 +0200 Subject: [PATCH 073/214] codegen: support nil strings/seqs in more places --- compiler/ccgexprs.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a2789138b7..9a6d5e4257 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -882,7 +882,7 @@ proc genIndexCheck(p: BProc; arr, idx: TLoc) = rdCharLoc(idx), first, intLiteral(lastOrd(ty))) of tySequence, tyString: linefmt(p, cpsStmts, - "if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", + "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", rdLoc(idx), rdLoc(arr), lenField(p)) else: discard @@ -907,11 +907,11 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if optBoundsCheck in p.options: if ty.kind == tyString: linefmt(p, cpsStmts, - "if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", + "if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", rdLoc(b), rdLoc(a), lenField(p)) else: linefmt(p, cpsStmts, - "if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", + "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", rdLoc(b), rdLoc(a), lenField(p)) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: @@ -1073,7 +1073,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: - addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)]) + addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) add(appends, rfmt(p.module, "#appendString($1, $2);$n", rdLoc(dest), rdLoc(a))) linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", @@ -1417,7 +1417,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage) of tyString, tySequence: putIntoDest(p, b, e, - "$1->data, $1->$2" % [rdLoc(a), lenField(p)], a.storage) + "$1->data, ($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)], a.storage) of tyArray: putIntoDest(p, b, e, "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.storage) From 84c4e7a50267c7a7d1fa437b27b2e27d9c76f896 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 10:00:31 +0200 Subject: [PATCH 074/214] make tests green again --- tests/errmsgs/tproper_stacktrace2.nim | 4 ++-- tests/manyloc/argument_parser/argument_parser.nim | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/errmsgs/tproper_stacktrace2.nim b/tests/errmsgs/tproper_stacktrace2.nim index 5f312b8703..44b208c87d 100644 --- a/tests/errmsgs/tproper_stacktrace2.nim +++ b/tests/errmsgs/tproper_stacktrace2.nim @@ -3,7 +3,7 @@ discard """ exitcode: 1 """ -proc returnsNil(): string = return nil +proc returnsNil(): ref int = return nil iterator fields*(a, b: int): int = if a == b: @@ -17,6 +17,6 @@ proc main(): string = result = "" for i in fields(0, 1): let x = returnsNil() - result &= "string literal " & $x + result &= "string literal " & $x[] echo main() diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index 14352066d4..1095a893e0 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -209,7 +209,7 @@ proc `$`*(data: Tcommandline_results): string = # - Parse code -template raise_or_quit(exception, message: expr): stmt {.immediate.} = +template raise_or_quit(exception, message: untyped) = ## Avoids repeating if check based on the default quit_on_failure variable. ## ## As a special case, if message has a zero length the call to quit won't @@ -230,15 +230,15 @@ template run_custom_proc(parsed_parameter: Tparsed_parameter, ## ## Pass in the string of the parameter triggering the call. If the if not custom_validator.isNil: + try: + let message = custom_validator(parameter, parsed_parameter) + if not message.isNil and message.len > 0: + raise_or_quit(ValueError, ("Failed to validate value for " & + "parameter $1:\n$2" % [escape(parameter), message])) except: raise_or_quit(ValueError, ("Couldn't run custom proc for " & "parameter $1:\n$2" % [escape(parameter), getCurrentExceptionMsg()])) - let message = custom_validator(parameter, parsed_parameter) - if not message.isNil and message.len > 0: - raise_or_quit(ValueError, ("Failed to validate value for " & - "parameter $1:\n$2" % [escape(parameter), message])) - proc parse_parameter(quit_on_failure: bool, param, value: string, param_kind: Tparam_kind): Tparsed_parameter = From aded62520b07fe4d03c36de8999b050b5678c4b8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 11:12:23 +0200 Subject: [PATCH 075/214] string to cstring conversions produce the empty C string for nil; this will be consistent with alternative string implementations --- changelog.md | 5 ++++- compiler/ccgcalls.nim | 8 ++++---- compiler/ccgexprs.nim | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 8ac02a388a..17c169d227 100644 --- a/changelog.md +++ b/changelog.md @@ -11,7 +11,7 @@ to deal with! - Indexing into a ``cstring`` for the JS target is now mapped to ``charCodeAt``. -- Assignments that would "slice" an object into its supertype are not prevented +- Assignments that would "slice" an object into its supertype are now prevented at runtime. Use ``ref object`` with inheritance rather than ``object`` with inheritance to prevent this issue. @@ -81,6 +81,9 @@ Imported exceptions can be raised and caught just like Nim exceptions. More details in language manual. +- ``nil`` for strings/seqs is finally gone. Instead the default value for + these is ``"" / @[]``. + ### Tool changes - ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 5f14b68046..2323d1f262 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -125,15 +125,15 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = of tyString, tySequence: if skipTypes(n.typ, abstractInst).kind == tyVar and not compileToCpp(p.module): - result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)] + result = "(*$1)->data, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p)] else: - result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)] + result = "$1->data, ($1 ? $1->$2 : 0)" % [a.rdLoc, lenField(p)] of tyArray: result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))] of tyPtr, tyRef: case lastSon(a.t).kind of tyString, tySequence: - result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)] + result = "(*$1)->data, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p)] of tyArray: result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))] else: @@ -143,7 +143,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} = var a: TLoc initLocExpr(p, n.sons[0], a) - result = "$1->data" % [a.rdLoc] + result = "($1 ? $1->data : \"\")" % [a.rdLoc] proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = var a: TLoc diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 9a6d5e4257..acf4c19753 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1740,7 +1740,7 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) = proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc initLocExpr(p, n.sons[0], a) - putIntoDest(p, d, n, "$1->data" % [rdLoc(a)], + putIntoDest(p, d, n, "($1 ? $1->data : \"\")" % [rdLoc(a)], a.storage) proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = From 13a380bca6d64310eb1383434519b153f1b48e57 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 13:10:45 +0200 Subject: [PATCH 076/214] make tests green --- compiler/ccgcalls.nim | 2 +- compiler/ccgexprs.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 2323d1f262..2ddc88509b 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -143,7 +143,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} = var a: TLoc initLocExpr(p, n.sons[0], a) - result = "($1 ? $1->data : \"\")" % [a.rdLoc] + result = "($1 ? $1->data : (NCSTRING)\"\")" % [a.rdLoc] proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = var a: TLoc diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index acf4c19753..dde3d6e708 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1740,7 +1740,7 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) = proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc initLocExpr(p, n.sons[0], a) - putIntoDest(p, d, n, "($1 ? $1->data : \"\")" % [rdLoc(a)], + putIntoDest(p, d, n, "($1 ? $1->data : (NCSTRING)\"\")" % [rdLoc(a)], a.storage) proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = From e53dc66a18a091a3ac67d7ccfb814a00d00d08d1 Mon Sep 17 00:00:00 2001 From: data-man Date: Sat, 28 Apr 2018 14:47:15 +0300 Subject: [PATCH 077/214] Compiler: show compile timestamps --- compiler/commands.nim | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 06b487cf04..9ae97b81d3 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -54,6 +54,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; const HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" & + "Compiled at $4 $5\n" & "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n" const @@ -68,7 +69,8 @@ const proc getCommandLineDesc(): string = result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name]) & Usage + CPU[platform.hostCPU].name, CompileDate, CompileTime]) & + Usage proc helpOnError(pass: TCmdLinePass) = if pass == passCmd1: @@ -79,7 +81,8 @@ proc writeAdvancedUsage(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(`%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name]) & AdvancedUsage, + CPU[platform.hostCPU].name, CompileDate, CompileTime]) & + AdvancedUsage, {msgStdout}) msgQuit(0) @@ -87,7 +90,8 @@ proc writeFullhelp(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(`%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name]) & Usage & AdvancedUsage, + CPU[platform.hostCPU].name, CompileDate, CompileTime]) & + Usage & AdvancedUsage, {msgStdout}) msgQuit(0) @@ -95,7 +99,7 @@ proc writeVersionInfo(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(`%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name]), + CPU[platform.hostCPU].name, CompileDate, CompileTime]), {msgStdout}) const gitHash = gorge("git log -n 1 --format=%H").strip From f64f9e50cca38db24f68ee70d979fd55b1c49868 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 15:13:44 +0200 Subject: [PATCH 078/214] correct comparisons for nil strings/seqs --- compiler/ccgexprs.nim | 14 +++++----- compiler/condsyms.nim | 2 +- compiler/vmgen.nim | 1 + lib/impure/nre.nim | 1 - lib/system.nim | 11 ++++---- lib/system/sysstr.nim | 29 ++++++++++++++------ tests/system/toString.nim | 56 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 91 insertions(+), 23 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index dde3d6e708..562d6d1657 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -980,10 +980,10 @@ proc genEcho(p: BProc, n: PNode) = var a: TLoc for it in n.sons: if it.skipConv.kind == nkNilLit: - add(args, ", \"nil\"") + add(args, ", \"\"") else: initLocExpr(p, it, a) - addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)]) + addf(args, ", $1? ($1)->data:\"\"", [rdLoc(a)]) p.module.includeHeader("") linefmt(p, cpsStmts, """Genode::log(""$1);$n""", args) else: @@ -1755,16 +1755,14 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = var x: TLoc var a = e.sons[1] var b = e.sons[2] - if (a.kind == nkNilLit) or (b.kind == nkNilLit): - binaryExpr(p, e, d, "($1 == $2)") - elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""): + if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "": initLocExpr(p, e.sons[2], x) putIntoDest(p, d, e, - rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p))) - elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""): + 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, - rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p))) + rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) else: binaryExpr(p, e, d, "#eqStrings($1, $2)") diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 028aedb5b5..08dda9b6a8 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -82,7 +82,6 @@ proc countDefinedSymbols*(): int = proc initDefines*() = gSymbols = newStringTable(modeStyleInsensitive) - defineSymbol("nimrod") # 'nimrod' is always defined # for bootstrapping purposes and old code: defineSymbol("nimhygiene") defineSymbol("niminheritable") @@ -115,3 +114,4 @@ proc initDefines*() = defineSymbol("nimHasNilChecks") defineSymbol("nimSymKind") defineSymbol("nimVmEqIdent") + defineSymbol("nimNoNil") diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index c3eaf89461..0544dc311f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1553,6 +1553,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = result = newNodeIT(nkFloatLit, info, t) of tyCString, tyString: result = newNodeIT(nkStrLit, info, t) + result.strVal = "" of tyVar, tyLent, tyPointer, tyPtr, tySequence, tyExpr, tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil: result = newNodeIT(nkNilLit, info, t) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 3d4afc0ae1..582f5ab3bc 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -645,7 +645,6 @@ template replaceImpl(str: string, pattern: Regex, let bounds = match.matchBounds result.add(str.substr(lastIdx, bounds.a - 1)) let nextVal = replacement - assert(nextVal != nil) result.add(nextVal) lastIdx = bounds.b + 1 diff --git a/lib/system.nim b/lib/system.nim index 523a25d641..5c0970f853 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2412,8 +2412,9 @@ proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} = if seqToPtr(x) == seqToPtr(y): return true - if x.isNil or y.isNil: - return false + when not defined(nimNoNil): + if x.isNil or y.isNil: + return false if x.len != y.len: return false @@ -4010,18 +4011,18 @@ proc addQuoted*[T](s: var string, x: T) = when hasAlloc: # XXX: make these the default (or implement the NilObject optimization) - proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect.} = + proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect, deprecated.} = ## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case, ## ``x`` becomes ``@[y]`` if x == nil: x = @[y] else: x.add(y) - proc safeAdd*(x: var string, y: char) = + proc safeAdd*(x: var string, y: char) {.noSideEffect, deprecated.} = ## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""`` if x == nil: x = "" x.add(y) - proc safeAdd*(x: var string, y: string) = + proc safeAdd*(x: var string, y: string) {.noSideEffect, deprecated.} = ## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that ## case, ``x`` becomes ``y`` if x == nil: x = y diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 9e7ee903f3..bba59e9309 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -22,21 +22,34 @@ proc resize(old: int): int {.inline.} = proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} = if a == b: return 0 - if a == nil: return -1 - if b == nil: return 1 - let minlen = min(a.len, b.len) + when defined(nimNoNil): + let alen = if a == nil: 0 else: a.len + let blen = if b == nil: 0 else: b.len + else: + if a == nil: return -1 + if b == nil: return 1 + let alen = a.len + let blen = b.len + let minlen = min(alen, blen) if minlen > 0: result = c_memcmp(addr a.data, addr b.data, minlen.csize) if result == 0: - result = a.len - b.len + result = alen - blen else: - result = a.len - b.len + result = alen - blen proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} = if a == b: return true - if a == nil or b == nil: return false - return a.len == b.len and - equalMem(addr(a.data), addr(b.data), a.len) + when defined(nimNoNil): + let alen = if a == nil: 0 else: a.len + let blen = if b == nil: 0 else: b.len + else: + if a == nil or b == nil: return false + let alen = a.len + let blen = b.len + if alen == blen: + if alen == 0: return true + return equalMem(addr(a.data), addr(b.data), alen) when declared(allocAtomic): template allocStr(size: untyped): untyped = diff --git a/tests/system/toString.nim b/tests/system/toString.nim index ea9d6b05b8..37c678a748 100644 --- a/tests/system/toString.nim +++ b/tests/system/toString.nim @@ -51,3 +51,59 @@ import strutils let arr = ['H','e','l','l','o',' ','W','o','r','l','d','!','\0'] doAssert $arr == "['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\\x00']" doAssert $cstring(unsafeAddr arr) == "Hello World!" + +proc takes(c: cstring) = + doAssert c == "" + +proc testm() = + var x: string + # nil is mapped to "": + takes(x) + +testm() + +# nil tests +var xx: seq[string] +var yy: string +doAssert xx == @[] +doAssert yy == "" + +proc bar(arg: cstring): void = + doAssert arg[0] == '\0' + +proc baz(arg: openarray[char]): void = + doAssert arg.len == 0 + +proc stringCompare(): void = + var a,b,c,d,e,f,g: string + a.add 'a' + doAssert a == "a" + b.add "bee" + doAssert b == "bee" + b.add g + doAssert b == "bee" + c.add 123.456 + doAssert c == "123.456" + d.add 123456 + doAssert d == "123456" + + doAssert e == "" + doAssert "" == e + doAssert nil == e + doAssert e == nil + doAssert f == g + doAssert "" == "" + doAssert "" == nil + doAssert nil == "" + + g.setLen(10) + doAssert g == "\0\0\0\0\0\0\0\0\0\0" + doAssert "" != "\0\0\0\0\0\0\0\0\0\0" + + var nilstring: string + bar(nilstring) + baz(nilstring) + +stringCompare() +static: + stringCompare() \ No newline at end of file From 4adc31ee3d5d56e1566da746b464ec11a6865863 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 18:23:54 +0200 Subject: [PATCH 079/214] stuff that is green --- compiler/semcall.nim | 33 ++++++++++++++++++--------------- compiler/semexprs.nim | 3 ++- compiler/sigmatch.nim | 24 +++++++++++++++++------- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index f443339f59..0df9435314 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -59,7 +59,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, filter: TSymKinds, best, alt: var TCandidate, errors: var CandidateErrors, - diagnosticsFlag = false) = + diagnosticsFlag: bool) = var o: TOverloadIter var sym = initOverloadIter(o, c, headSymbol) var scope = o.lastOverloadScope @@ -68,6 +68,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, # This can occur in cases like 'init(a, 1, (var b = new(Type2); b))' let counterInitial = c.currentScope.symbols.counter var syms: seq[tuple[s: PSym, scope: int]] + var noSyms = true var nextSymIndex = 0 while sym != nil: if sym.kind in filter: @@ -102,18 +103,20 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, var cmp = cmpCandidates(best, z) if cmp < 0: best = z # x is better than the best so far elif cmp == 0: alt = z # x is as good as the best so far - elif errors != nil or z.diagnostics != nil: - errors.safeAdd(CandidateError( + elif errors.enabled or z.diagnostics.enabled: + errors.s.safeAdd(CandidateError( sym: sym, unmatchedVarParam: int z.mutabilityProblem, firstMismatch: z.firstMismatch, diagnostics: z.diagnostics)) + errors.enabled = true else: # Symbol table has been modified. Restart and pre-calculate all syms # before any further candidate init and compare. SLOW, but rare case. syms = initCandidateSymbols(c, headSymbol, initialBinding, filter, best, alt, o, diagnosticsFlag) - if syms == nil: + noSyms = false + if noSyms: sym = nextOverloadIter(o, c, headSymbol) scope = o.lastOverloadScope elif nextSymIndex < syms.len: @@ -148,7 +151,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): # we do a pre-analysis. If all types produce the same string, we will add # module information. let proto = describeArgs(c, n, 1, preferName) - for err in errors: + for err in errors.s: var errProto = "" let n = err.sym.typ.n for i in countup(1, n.len - 1): @@ -162,7 +165,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): break var candidates = "" - for err in errors: + for err in errors.s: if err.sym.kind in routineKinds and err.sym.ast != nil: add(candidates, renderTree(err.sym.ast, {renderNoBody, renderNoComments, renderNoPragmas})) @@ -194,7 +197,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): candidates.add(" for a 'var' type a variable needs to be passed, but '" & renderNotLValue(n[err.unmatchedVarParam]) & "' is immutable\n") - for diag in err.diagnostics: + for diag in err.diagnostics.s: candidates.add(diag & "\n") result = (prefer, candidates) @@ -206,7 +209,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = if errorOutputs == {}: # fail fast: globalError(n.info, errTypeMismatch, "") - if errors.isNil or errors.len == 0: + if errors.s.len == 0: localError(n.info, errExprXCannotBeCalled, n[0].renderTree) return @@ -219,17 +222,18 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = localError(n.info, errGenerated, result & "\nexpression: " & $n) proc bracketNotFoundError(c: PContext; n: PNode) = - var errors: CandidateErrors = @[] + var errors = CandidateErrors(enabled: true, s: @[]) var o: TOverloadIter let headSymbol = n[0] var symx = initOverloadIter(o, c, headSymbol) while symx != nil: if symx.kind in routineKinds: - errors.add(CandidateError(sym: symx, + errors.s.add(CandidateError(sym: symx, unmatchedVarParam: 0, firstMismatch: 0, - diagnostics: nil)) + diagnostics: OptionalStringSeq(enabled: false, s: @[]))) + errors.enabled = true symx = nextOverloadIter(o, c, headSymbol) - if errors.len == 0: + if errors.s.len == 0: localError(n.info, "could not resolve: " & $n) else: notFoundError(c, n, errors) @@ -423,12 +427,11 @@ proc tryDeref(n: PNode): PNode = proc semOverloadedCall(c: PContext, n, nOrig: PNode, filter: TSymKinds, flags: TExprFlags): PNode = - var errors: CandidateErrors = if efExplain in flags: @[] - else: nil + var errors = CandidateErrors(enabled: efExplain in flags, s: nil) var r = resolveOverloads(c, n, nOrig, filter, flags, errors) if r.state == csMatch: # this may be triggered, when the explain pragma is used - if errors.len > 0: + if errors.s.len > 0: let (_, candidates) = presentFailedCandidates(c, n, errors) message(n.info, hintUserRaw, "Non-matching candidates for " & renderTree(n) & "\n" & diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 22dee81b71..66fe81ed30 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -305,7 +305,8 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = maybeLiftType(t2, c, n.info) var m: TCandidate initCandidate(c, m, t2) - if efExplain in flags: m.diagnostics = @[] + if efExplain in flags: + m.diagnostics = OptionalStringSeq(enabled: true, s: @[]) let match = typeRel(m, t2, t1) >= isSubtype # isNone result = newIntNode(nkIntLit, ord(match)) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 552d2cdca7..0426a22f38 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -22,12 +22,18 @@ type TCandidateState* = enum csEmpty, csMatch, csNoMatch + OptionalStringSeq* = object + enabled*: bool + s*: seq[string] + CandidateError* = object sym*: PSym unmatchedVarParam*, firstMismatch*: int - diagnostics*: seq[string] + diagnostics*: OptionalStringSeq # seq[string] - CandidateErrors* = seq[CandidateError] + CandidateErrors* = object + enabled*: bool + s*: seq[CandidateError] TCandidate* = object c*: PContext @@ -60,7 +66,8 @@ type # matching. they will be reset if the matching # is not successful. may replace the bindings # table in the future. - diagnostics*: seq[string] # when this is not nil, the matching process + diagnostics*: OptionalStringSeq # \ + # when diagnosticsEnabled, the matching process # will collect extra diagnostics that will be # displayed to the user. # triggered when overload resolution fails @@ -124,7 +131,8 @@ proc put(c: var TCandidate, key, val: PType) {.inline.} = idTablePut(c.bindings, key, val.skipIntLit) proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, - binding: PNode, calleeScope = -1, diagnostics = false) = + binding: PNode, calleeScope = -1, + diagnosticsEnabled = false) = initCandidateAux(ctx, c, callee.typ) c.calleeSym = callee if callee.kind in skProcKinds and calleeScope == -1: @@ -139,7 +147,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, c.calleeScope = 1 else: c.calleeScope = calleeScope - c.diagnostics = if diagnostics: @[] else: nil + c.diagnostics = OptionalStringSeq(enabled: diagnosticsEnabled, s: @[]) c.magic = c.calleeSym.magic initIdTable(c.bindings) if binding != nil and callee.kind in routineKinds: @@ -717,7 +725,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = diagnostics: seq[string] errorPrefix: string flags: TExprFlags = {} - collectDiagnostics = m.diagnostics != nil or + collectDiagnostics = m.diagnostics.enabled or sfExplain in typeClass.sym.flags if collectDiagnostics: @@ -736,7 +744,9 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = if collectDiagnostics: writelnHook = oldWriteHook - for msg in diagnostics: m.diagnostics.safeAdd msg + for msg in diagnostics: + m.diagnostics.s.safeAdd msg + m.diagnostics.enabled = true if checkedBody == nil: return nil From 6408646b02a8a7bc7a7182277499978cd16fcd70 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 18:37:45 +0200 Subject: [PATCH 080/214] minor speedup: concept tests still green --- compiler/semcall.nim | 7 ++++--- compiler/semexprs.nim | 3 ++- compiler/sigmatch.nim | 19 +++++++++---------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 0df9435314..3a12ca980e 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -103,7 +103,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, var cmp = cmpCandidates(best, z) if cmp < 0: best = z # x is better than the best so far elif cmp == 0: alt = z # x is as good as the best so far - elif errors.enabled or z.diagnostics.enabled: + elif errors.enabled or z.diagnosticsEnabled: errors.s.safeAdd(CandidateError( sym: sym, unmatchedVarParam: int z.mutabilityProblem, @@ -197,7 +197,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): candidates.add(" for a 'var' type a variable needs to be passed, but '" & renderNotLValue(n[err.unmatchedVarParam]) & "' is immutable\n") - for diag in err.diagnostics.s: + for diag in err.diagnostics: candidates.add(diag & "\n") result = (prefer, candidates) @@ -230,7 +230,8 @@ proc bracketNotFoundError(c: PContext; n: PNode) = if symx.kind in routineKinds: errors.s.add(CandidateError(sym: symx, unmatchedVarParam: 0, firstMismatch: 0, - diagnostics: OptionalStringSeq(enabled: false, s: @[]))) + diagnostics: nil, + enabled: false)) errors.enabled = true symx = nextOverloadIter(o, c, headSymbol) if errors.s.len == 0: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 66fe81ed30..feca087fce 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -306,7 +306,8 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = var m: TCandidate initCandidate(c, m, t2) if efExplain in flags: - m.diagnostics = OptionalStringSeq(enabled: true, s: @[]) + m.diagnostics = @[] + m.diagnosticsEnabled = true let match = typeRel(m, t2, t1) >= isSubtype # isNone result = newIntNode(nkIntLit, ord(match)) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 0426a22f38..2b105f48ae 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -22,14 +22,11 @@ type TCandidateState* = enum csEmpty, csMatch, csNoMatch - OptionalStringSeq* = object - enabled*: bool - s*: seq[string] - CandidateError* = object sym*: PSym unmatchedVarParam*, firstMismatch*: int - diagnostics*: OptionalStringSeq # seq[string] + diagnostics*: seq[string] + enabled*: bool CandidateErrors* = object enabled*: bool @@ -66,7 +63,7 @@ type # matching. they will be reset if the matching # is not successful. may replace the bindings # table in the future. - diagnostics*: OptionalStringSeq # \ + diagnostics*: seq[string] # \ # when diagnosticsEnabled, the matching process # will collect extra diagnostics that will be # displayed to the user. @@ -77,6 +74,7 @@ type inheritancePenalty: int # to prefer closest father object type firstMismatch*: int # position of the first type mismatch for # better error messages + diagnosticsEnabled*: bool TTypeRelFlag* = enum trDontBind @@ -147,7 +145,8 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, c.calleeScope = 1 else: c.calleeScope = calleeScope - c.diagnostics = OptionalStringSeq(enabled: diagnosticsEnabled, s: @[]) + c.diagnostics = if diagnosticsEnabled: @[] else: nil + c.diagnosticsEnabled = diagnosticsEnabled c.magic = c.calleeSym.magic initIdTable(c.bindings) if binding != nil and callee.kind in routineKinds: @@ -725,7 +724,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = diagnostics: seq[string] errorPrefix: string flags: TExprFlags = {} - collectDiagnostics = m.diagnostics.enabled or + collectDiagnostics = m.diagnosticsEnabled or sfExplain in typeClass.sym.flags if collectDiagnostics: @@ -745,8 +744,8 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = if collectDiagnostics: writelnHook = oldWriteHook for msg in diagnostics: - m.diagnostics.s.safeAdd msg - m.diagnostics.enabled = true + m.diagnostics.safeAdd msg + m.diagnosticsEnabled = true if checkedBody == nil: return nil From 9d77f61038ddabeb4b59847d709e6d722e743082 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 18:48:18 +0200 Subject: [PATCH 081/214] sigmatch: speed it up --- compiler/semcall.nim | 35 ++++++++++++++++++----------------- compiler/sigmatch.nim | 4 +--- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 3a12ca980e..aa53fda3b4 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -59,7 +59,8 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, filter: TSymKinds, best, alt: var TCandidate, errors: var CandidateErrors, - diagnosticsFlag: bool) = + diagnosticsFlag: bool, + errorsEnabled: bool) = var o: TOverloadIter var sym = initOverloadIter(o, c, headSymbol) var scope = o.lastOverloadScope @@ -103,13 +104,12 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, var cmp = cmpCandidates(best, z) if cmp < 0: best = z # x is better than the best so far elif cmp == 0: alt = z # x is as good as the best so far - elif errors.enabled or z.diagnosticsEnabled: - errors.s.safeAdd(CandidateError( + elif errorsEnabled or z.diagnosticsEnabled: + errors.safeAdd(CandidateError( sym: sym, unmatchedVarParam: int z.mutabilityProblem, firstMismatch: z.firstMismatch, diagnostics: z.diagnostics)) - errors.enabled = true else: # Symbol table has been modified. Restart and pre-calculate all syms # before any further candidate init and compare. SLOW, but rare case. @@ -151,7 +151,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): # we do a pre-analysis. If all types produce the same string, we will add # module information. let proto = describeArgs(c, n, 1, preferName) - for err in errors.s: + for err in errors: var errProto = "" let n = err.sym.typ.n for i in countup(1, n.len - 1): @@ -165,7 +165,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): break var candidates = "" - for err in errors.s: + for err in errors: if err.sym.kind in routineKinds and err.sym.ast != nil: add(candidates, renderTree(err.sym.ast, {renderNoBody, renderNoComments, renderNoPragmas})) @@ -209,7 +209,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = if errorOutputs == {}: # fail fast: globalError(n.info, errTypeMismatch, "") - if errors.s.len == 0: + if errors.len == 0: localError(n.info, errExprXCannotBeCalled, n[0].renderTree) return @@ -222,26 +222,26 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = localError(n.info, errGenerated, result & "\nexpression: " & $n) proc bracketNotFoundError(c: PContext; n: PNode) = - var errors = CandidateErrors(enabled: true, s: @[]) + var errors: CandidateErrors = @[] var o: TOverloadIter let headSymbol = n[0] var symx = initOverloadIter(o, c, headSymbol) while symx != nil: if symx.kind in routineKinds: - errors.s.add(CandidateError(sym: symx, + errors.add(CandidateError(sym: symx, unmatchedVarParam: 0, firstMismatch: 0, diagnostics: nil, enabled: false)) - errors.enabled = true symx = nextOverloadIter(o, c, headSymbol) - if errors.s.len == 0: + if errors.len == 0: localError(n.info, "could not resolve: " & $n) else: notFoundError(c, n, errors) proc resolveOverloads(c: PContext, n, orig: PNode, filter: TSymKinds, flags: TExprFlags, - errors: var CandidateErrors): TCandidate = + errors: var CandidateErrors, + errorsEnabled: bool): TCandidate = var initialBinding: PNode var alt: TCandidate var f = n.sons[0] @@ -254,7 +254,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode, template pickBest(headSymbol) = pickBestCandidate(c, headSymbol, n, orig, initialBinding, - filter, result, alt, errors, efExplain in flags) + filter, result, alt, errors, efExplain in flags, + errorsEnabled) pickBest(f) let overloadsState = result.state @@ -428,11 +429,11 @@ proc tryDeref(n: PNode): PNode = proc semOverloadedCall(c: PContext, n, nOrig: PNode, filter: TSymKinds, flags: TExprFlags): PNode = - var errors = CandidateErrors(enabled: efExplain in flags, s: nil) - var r = resolveOverloads(c, n, nOrig, filter, flags, errors) + var errors: CandidateErrors = if efExplain in flags: @[] else: nil + var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags) if r.state == csMatch: # this may be triggered, when the explain pragma is used - if errors.s.len > 0: + if errors.len > 0: let (_, candidates) = presentFailedCandidates(c, n, errors) message(n.info, hintUserRaw, "Non-matching candidates for " & renderTree(n) & "\n" & @@ -447,7 +448,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, # into sigmatch with hidden conversion produced there # n.sons[1] = n.sons[1].tryDeref - var r = resolveOverloads(c, n, nOrig, filter, flags, errors) + var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags) if r.state == csMatch: result = semResolvedCall(c, n, r) else: # get rid of the deref again for a better error message: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 2b105f48ae..4263ef5813 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -28,9 +28,7 @@ type diagnostics*: seq[string] enabled*: bool - CandidateErrors* = object - enabled*: bool - s*: seq[CandidateError] + CandidateErrors* = seq[CandidateError] TCandidate* = object c*: PContext From 9b8603adcd7ce8fa9563137bcbe6c350e07a6fe0 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 28 Apr 2018 21:59:43 +0200 Subject: [PATCH 082/214] strutils: code cleanups and do not rely on the terminating binary zero anymore --- compiler/ccgexprs.nim | 15 +- lib/pure/strutils.nim | 383 +++++++++++------------------------------- 2 files changed, 101 insertions(+), 297 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 562d6d1657..eb67db2b31 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -63,6 +63,10 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = of tyNil: result = genNilStringLiteral(p.module, n.info) of tyString: + # with the new semantics for 'nil' strings, we can map "" to nil and + # save tons of allocations: + #if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info) + #else: result = genStringLiteral(p.module, n) else: if n.strVal.isNil: result = rope("NIM_NIL") @@ -905,14 +909,9 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: if optBoundsCheck in p.options: - if ty.kind == tyString: - linefmt(p, cpsStmts, - "if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(b), rdLoc(a), lenField(p)) - else: - linefmt(p, cpsStmts, - "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(b), rdLoc(a), lenField(p)) + linefmt(p, cpsStmts, + "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", + rdLoc(b), rdLoc(a), lenField(p)) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: a.r = rfmt(nil, "(*$1)", a.r) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index cdc5ec4f9d..4500a163fe 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -106,6 +106,12 @@ proc isUpperAscii*(c: char): bool {.noSideEffect, procvar, ## This checks ASCII characters only. return c in {'A'..'Z'} +template isImpl(call) = + if s.len == 0: return false + result = true + for c in s: + if not call(c): return false + proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsAlphaAsciiStr".} = ## Checks whether or not `s` is alphabetical. @@ -114,12 +120,7 @@ proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar, ## Returns true if all characters in `s` are ## alphabetic and there is at least one character ## in `s`. - if s.len() == 0: - return false - - result = true - for c in s: - if not c.isAlphaAscii(): return false + isImpl isAlphaAscii proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsAlphaNumericStr".} = @@ -129,13 +130,7 @@ proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar, ## Returns true if all characters in `s` are ## alpanumeric and there is at least one character ## in `s`. - if s.len() == 0: - return false - - result = true - for c in s: - if not c.isAlphaNumeric(): - return false + isImpl isAlphaNumeric proc isDigit*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsDigitStr".} = @@ -145,13 +140,7 @@ proc isDigit*(s: string): bool {.noSideEffect, procvar, ## Returns true if all characters in `s` are ## numeric and there is at least one character ## in `s`. - if s.len() == 0: - return false - - result = true - for c in s: - if not c.isDigit(): - return false + isImpl isDigit proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsSpaceAsciiStr".} = @@ -159,13 +148,7 @@ proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar, ## ## Returns true if all characters in `s` are whitespace ## characters and there is at least one character in `s`. - if s.len() == 0: - return false - - result = true - for c in s: - if not c.isSpaceAscii(): - return false + isImpl isSpaceAscii proc isLowerAscii*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsLowerAsciiStr".} = @@ -174,13 +157,7 @@ proc isLowerAscii*(s: string): bool {.noSideEffect, procvar, ## This checks ASCII characters only. ## Returns true if all characters in `s` are lower case ## and there is at least one character in `s`. - if s.len() == 0: - return false - - for c in s: - if not c.isLowerAscii(): - return false - true + isImpl isLowerAscii proc isUpperAscii*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsUpperAsciiStr".} = @@ -189,13 +166,7 @@ proc isUpperAscii*(s: string): bool {.noSideEffect, procvar, ## This checks ASCII characters only. ## Returns true if all characters in `s` are upper case ## and there is at least one character in `s`. - if s.len() == 0: - return false - - for c in s: - if not c.isUpperAscii(): - return false - true + isImpl isUpperAscii proc toLowerAscii*(c: char): char {.noSideEffect, procvar, rtl, extern: "nsuToLowerAsciiChar".} = @@ -209,6 +180,11 @@ proc toLowerAscii*(c: char): char {.noSideEffect, procvar, else: result = c +template toImpl(call) = + result = newString(len(s)) + for i in 0..len(s) - 1: + result[i] = call(s[i]) + proc toLowerAscii*(s: string): string {.noSideEffect, procvar, rtl, extern: "nsuToLowerAsciiStr".} = ## Converts `s` into lower case. @@ -216,9 +192,7 @@ proc toLowerAscii*(s: string): string {.noSideEffect, procvar, ## This works only for the letters ``A-Z``. See `unicode.toLower ## `_ for a version that works for any Unicode ## character. - result = newString(len(s)) - for i in 0..len(s) - 1: - result[i] = toLowerAscii(s[i]) + toImpl toLowerAscii proc toUpperAscii*(c: char): char {.noSideEffect, procvar, rtl, extern: "nsuToUpperAsciiChar".} = @@ -239,147 +213,15 @@ proc toUpperAscii*(s: string): string {.noSideEffect, procvar, ## This works only for the letters ``A-Z``. See `unicode.toUpper ## `_ for a version that works for any Unicode ## character. - result = newString(len(s)) - for i in 0..len(s) - 1: - result[i] = toUpperAscii(s[i]) + toImpl toUpperAscii proc capitalizeAscii*(s: string): string {.noSideEffect, procvar, rtl, extern: "nsuCapitalizeAscii".} = ## Converts the first character of `s` into upper case. ## ## This works only for the letters ``A-Z``. - result = toUpperAscii(s[0]) & substr(s, 1) - -proc isSpace*(c: char): bool {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuIsSpaceChar".}= - ## Checks whether or not `c` is a whitespace character. - ## - ## **Deprecated since version 0.15.0**: use ``isSpaceAscii`` instead. - isSpaceAscii(c) - -proc isLower*(c: char): bool {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuIsLowerChar".}= - ## Checks whether or not `c` is a lower case character. - ## - ## This checks ASCII characters only. - ## - ## **Deprecated since version 0.15.0**: use ``isLowerAscii`` instead. - isLowerAscii(c) - -proc isUpper*(c: char): bool {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuIsUpperChar".}= - ## Checks whether or not `c` is an upper case character. - ## - ## This checks ASCII characters only. - ## - ## **Deprecated since version 0.15.0**: use ``isUpperAscii`` instead. - isUpperAscii(c) - -proc isAlpha*(c: char): bool {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuIsAlphaChar".}= - ## Checks whether or not `c` is alphabetical. - ## - ## This checks a-z, A-Z ASCII characters only. - ## - ## **Deprecated since version 0.15.0**: use ``isAlphaAscii`` instead. - isAlphaAscii(c) - -proc isAlpha*(s: string): bool {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuIsAlphaStr".}= - ## Checks whether or not `s` is alphabetical. - ## - ## This checks a-z, A-Z ASCII characters only. - ## Returns true if all characters in `s` are - ## alphabetic and there is at least one character - ## in `s`. - ## - ## **Deprecated since version 0.15.0**: use ``isAlphaAscii`` instead. - isAlphaAscii(s) - -proc isSpace*(s: string): bool {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuIsSpaceStr".}= - ## Checks whether or not `s` is completely whitespace. - ## - ## Returns true if all characters in `s` are whitespace - ## characters and there is at least one character in `s`. - ## - ## **Deprecated since version 0.15.0**: use ``isSpaceAscii`` instead. - isSpaceAscii(s) - -proc isLower*(s: string): bool {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuIsLowerStr".}= - ## Checks whether or not `s` contains all lower case characters. - ## - ## This checks ASCII characters only. - ## Returns true if all characters in `s` are lower case - ## and there is at least one character in `s`. - ## - ## **Deprecated since version 0.15.0**: use ``isLowerAscii`` instead. - isLowerAscii(s) - -proc isUpper*(s: string): bool {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuIsUpperStr".}= - ## Checks whether or not `s` contains all upper case characters. - ## - ## This checks ASCII characters only. - ## Returns true if all characters in `s` are upper case - ## and there is at least one character in `s`. - ## - ## **Deprecated since version 0.15.0**: use ``isUpperAscii`` instead. - isUpperAscii(s) - -proc toLower*(c: char): char {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuToLowerChar".} = - ## Converts `c` into lower case. - ## - ## This works only for the letters ``A-Z``. See `unicode.toLower - ## `_ for a version that works for any Unicode - ## character. - ## - ## **Deprecated since version 0.15.0**: use ``toLowerAscii`` instead. - toLowerAscii(c) - -proc toLower*(s: string): string {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuToLowerStr".} = - ## Converts `s` into lower case. - ## - ## This works only for the letters ``A-Z``. See `unicode.toLower - ## `_ for a version that works for any Unicode - ## character. - ## - ## **Deprecated since version 0.15.0**: use ``toLowerAscii`` instead. - toLowerAscii(s) - -proc toUpper*(c: char): char {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuToUpperChar".} = - ## Converts `c` into upper case. - ## - ## This works only for the letters ``A-Z``. See `unicode.toUpper - ## `_ for a version that works for any Unicode - ## character. - ## - ## **Deprecated since version 0.15.0**: use ``toUpperAscii`` instead. - toUpperAscii(c) - -proc toUpper*(s: string): string {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuToUpperStr".} = - ## Converts `s` into upper case. - ## - ## This works only for the letters ``A-Z``. See `unicode.toUpper - ## `_ for a version that works for any Unicode - ## character. - ## - ## **Deprecated since version 0.15.0**: use ``toUpperAscii`` instead. - toUpperAscii(s) - -proc capitalize*(s: string): string {.noSideEffect, procvar, - rtl, deprecated, extern: "nsuCapitalize".} = - ## Converts the first character of `s` into upper case. - ## - ## This works only for the letters ``A-Z``. - ## - ## **Deprecated since version 0.15.0**: use ``capitalizeAscii`` instead. - capitalizeAscii(s) + if s.len == 0: result = "" + else: result = toUpperAscii(s[0]) & substr(s, 1) proc normalize*(s: string): string {.noSideEffect, procvar, rtl, extern: "nsuNormalize".} = @@ -419,9 +261,9 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, rtl, extern: "nsuCmpIgnoreStyle", procvar.} = ## Semantically the same as ``cmp(normalize(a), normalize(b))``. It - ## is just optimized to not allocate temporary strings. This should + ## is just optimized to not allocate temporary strings. This should ## NOT be used to compare Nim identifier names. use `macros.eqIdent` - ## for that. Returns: + ## for that. Returns: ## ## | 0 iff a == b ## | < 0 iff a < b @@ -429,14 +271,22 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, var i = 0 var j = 0 while true: - while a[i] == '_': inc(i) - while b[j] == '_': inc(j) # BUGFIX: typo - var aa = toLowerAscii(a[i]) - var bb = toLowerAscii(b[j]) + while i < a.len and a[i] == '_': inc i + while j < b.len and b[j] == '_': inc j + var aa = if i < a.len: toLowerAscii(a[i]) else: '\0' + var bb = if j < b.len: toLowerAscii(b[j]) else: '\0' result = ord(aa) - ord(bb) - if result != 0 or aa == '\0': break - inc(i) - inc(j) + if result != 0: return result + # the characters are identical: + if i >= a.len: + # both cursors at the end: + if j >= b.len: return 0 + # not yet at the end of 'b': + return -1 + elif j >= b.len: + return 1 + inc i + inc j proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string @@ -451,7 +301,7 @@ proc strip*(s: string, leading = true, trailing = true, first = 0 last = len(s)-1 if leading: - while s[first] in chars: inc(first) + while first <= last and s[first] in chars: inc(first) if trailing: while last >= 0 and s[last] in chars: dec(last) result = substr(s, first, last) @@ -467,7 +317,9 @@ proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} = result[i] = chr(val mod 8 + ord('0')) val = val div 8 -proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrEmpty".} = +proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl, + extern: "nsuIsNilOrEmpty", + deprecated: "use 'x.len == 0' instead".} = ## Checks if `s` is nil or empty. result = len(s) == 0 @@ -486,7 +338,6 @@ proc substrEq(s: string, pos: int, substr: string): bool = var length = substr.len while i < length and s[pos+i] == substr[i]: inc i - return i == length # --------- Private templates for different split separators ----------- @@ -520,7 +371,7 @@ template oldSplit(s, seps, maxsplit) = var splits = maxsplit assert(not ('\0' in seps)) while last < len(s): - while s[last] in seps: inc(last) + while last < len(s) and s[last] in seps: inc(last) var first = last while last < len(s) and s[last] notin seps: inc(last) if first <= last-1: @@ -571,10 +422,7 @@ iterator split*(s: string, seps: set[char] = Whitespace, ## "08" ## "08.398990" ## - when defined(nimOldSplit): - oldSplit(s, seps, maxsplit) - else: - splitCommon(s, seps, maxsplit, 1) + splitCommon(s, seps, maxsplit, 1) iterator splitWhitespace*(s: string, maxsplit: int = -1): string = ## Splits the string ``s`` at whitespace stripping leading and trailing @@ -660,7 +508,6 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string = ## "is" ## "corrupted" ## - splitCommon(s, sep, maxsplit, sep.len) template rsplitCommon(s, sep, maxsplit, sepLen) = @@ -670,29 +517,21 @@ template rsplitCommon(s, sep, maxsplit, sepLen) = first = last splits = maxsplit startPos = 0 - # go to -1 in order to get separators at the beginning while first >= -1: while first >= 0 and not stringHasSep(s, first, sep): dec(first) - if splits == 0: # No more splits means set first to the beginning first = -1 - if first == -1: startPos = 0 else: startPos = first + sepLen - yield substr(s, startPos, last) - - if splits == 0: - break - + if splits == 0: break dec(splits) dec(first) - last = first iterator rsplit*(s: string, seps: set[char] = Whitespace, @@ -712,7 +551,6 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace, ## "foo" ## ## Substrings are separated from the right by the set of chars `seps` - rsplitCommon(s, seps, maxsplit, 1) iterator rsplit*(s: string, sep: char, @@ -779,14 +617,14 @@ iterator splitLines*(s: string): string = var first = 0 var last = 0 while true: - while s[last] notin {'\0', '\c', '\l'}: inc(last) + while last < s.len and s[last] notin {'\c', '\l'}: inc(last) yield substr(s, first, last-1) # skip newlines: + if last >= s.len: break if s[last] == '\l': inc(last) elif s[last] == '\c': inc(last) - if s[last] == '\l': inc(last) - else: break # was '\0' + if last < s.len and s[last] == '\l': inc(last) first = last proc splitLines*(s: string): seq[string] {.noSideEffect, @@ -811,7 +649,7 @@ proc countLines*(s: string): int {.noSideEffect, while i < s.len: case s[i] of '\c': - if s[i+1] == '\l': inc i + if i+1 < s.len and s[i+1] == '\l': inc i inc result of '\l': inc result else: discard @@ -1025,9 +863,9 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar, ## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores ## within `s` are ignored. var i = 0 - if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2) - elif s[i] == '#': inc(i) - while true: + if i+1 < s.len and s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2) + elif i < s.len and s[i] == '#': inc(i) + while i < s.len: case s[i] of '_': inc(i) of '0'..'9': @@ -1039,7 +877,6 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar, of 'A'..'F': result = result shl 4 or (ord(s[i]) - ord('A') + 10) inc(i) - of '\0': break else: raise newException(ValueError, "invalid integer: " & s) proc generateHexCharToValueMap(): string = @@ -1148,14 +985,6 @@ template spaces*(n: Natural): string = repeat(' ', n) ## echo text1 & spaces(max(0, width - text1.len)) & "|" ## echo text2 & spaces(max(0, width - text2.len)) & "|" -proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} = - ## deprecated: use repeat() or spaces() - repeat(c, count) - -proc repeatStr*(count: Natural, s: string): string {.deprecated.} = - ## deprecated: use repeat(string, count) or string.repeat(count) - repeat(s, count) - proc align*(s: string, count: Natural, padding = ' '): string {. noSideEffect, rtl, extern: "nsuAlignString".} = ## Aligns a string `s` with `padding`, so that it is of length `count`. @@ -1226,7 +1055,7 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[ var i = 0 while true: var j = i - var isSep = s[j] in seps + var isSep = j < s.len and s[j] in seps while j < s.len and (s[j] in seps) == isSep: inc(j) if j > i: yield (substr(s, i, j-1), isSep) @@ -1325,13 +1154,13 @@ proc startsWith*(s, prefix: string): bool {.noSideEffect, ## If ``prefix == ""`` true is returned. var i = 0 while true: - if prefix[i] == '\0': return true - if s[i] != prefix[i]: return false + if i >= prefix.len: return true + if i >= s.len or s[i] != prefix[i]: return false inc(i) proc startsWith*(s: string, prefix: char): bool {.noSideEffect, inline.} = ## Returns true iff ``s`` starts with ``prefix``. - result = s[0] == prefix + result = s.len > 0 and s[0] == prefix proc endsWith*(s, suffix: string): bool {.noSideEffect, rtl, extern: "nsuEndsWith".} = @@ -1343,11 +1172,11 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect, while i+j <% s.len: if s[i+j] != suffix[i]: return false inc(i) - if suffix[i] == '\0': return true + if i >= suffix.len: return true proc endsWith*(s: string, suffix: char): bool {.noSideEffect, inline.} = ## Returns true iff ``s`` ends with ``suffix``. - result = s[s.high] == suffix + result = s.len > 0 and s[s.high] == suffix proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect, rtl, extern: "nsuContinuesWith".} = @@ -1356,8 +1185,8 @@ proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect, ## If ``substr == ""`` true is returned. var i = 0 while true: - if substr[i] == '\0': return true - if s[i+start] != substr[i]: return false + if i >= substr.len: return true + if i+start >= s.len or s[i+start] != substr[i]: return false inc(i) proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0) @@ -1502,12 +1331,8 @@ proc find*(s, sub: string, start: Natural = 0, last: Natural = 0): int {.noSideE ## If `last` is unspecified, it defaults to `s.high`. ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - if sub.len > s.len: - return -1 - - if sub.len == 1: - return find(s, sub[0], start, last) - + if sub.len > s.len: return -1 + if sub.len == 1: return find(s, sub[0], start, last) var a {.noinit.}: SkipTable initSkipTable(a, sub) result = find(a, s, sub, start, last) @@ -1564,18 +1389,14 @@ proc center*(s: string, width: int, fillChar: char = ' '): string {. ## ## The original string is returned if `width` is less than or equal ## to `s.len`. - if width <= s.len: - return s - + if width <= s.len: return s result = newString(width) - # Left padding will be one fillChar # smaller if there are an odd number # of characters let charsLeft = (width - s.len) leftPadding = charsLeft div 2 - for i in 0 ..< width: if i >= leftPadding and i < leftPadding + s.len: # we are where the string should be located @@ -1593,27 +1414,22 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {. var i = 0 while true: i = s.find(sub, i) - if i < 0: - break - if overlapping: - inc i - else: - i += sub.len + if i < 0: break + if overlapping: inc i + else: i += sub.len inc result proc count*(s: string, sub: char): int {.noSideEffect, rtl, extern: "nsuCountChar".} = ## Count the occurrences of the character `sub` in the string `s`. for c in s: - if c == sub: - inc result + if c == sub: inc result proc count*(s: string, subs: set[char]): int {.noSideEffect, rtl, extern: "nsuCountCharSet".} = ## Count the occurrences of the group of character `subs` in the string `s`. for c in s: - if c in subs: - inc result + if c in subs: inc result proc quoteIfContainsWhite*(s: string): string {.deprecated.} = ## Returns ``'"' & s & '"'`` if `s` contains a space and does not @@ -1621,10 +1437,8 @@ proc quoteIfContainsWhite*(s: string): string {.deprecated.} = ## ## **DEPRECATED** as it was confused for shell quoting function. For this ## application use `osproc.quoteShell `_. - if find(s, {' ', '\t'}) >= 0 and s[0] != '"': - result = '"' & s & '"' - else: - result = s + if find(s, {' ', '\t'}) >= 0 and s[0] != '"': result = '"' & s & '"' + else: result = s proc contains*(s: string, c: char): bool {.noSideEffect.} = ## Same as ``find(s, c) >= 0``. @@ -1704,9 +1518,8 @@ proc multiReplace*(s: string, replacements: varargs[(string, string)]): string { ## Same as replace, but specialized for doing multiple replacements in a single ## pass through the input string. ## - ## Calling replace multiple times after each other is inefficient and result in too many allocations - ## follwed by immediate deallocations as portions of the string gets replaced. - ## multiReplace performs all replacements in a single pass. + ## multiReplace performs all replacements in a single pass, this means it can be used + ## to swap the occurences of "a" and "b", for instance. ## ## If the resulting string is not longer than the original input string, only a single ## memory allocation is required. @@ -1753,14 +1566,13 @@ proc parseOctInt*(s: string): int {.noSideEffect, ## of the following optional prefixes: ``0o``, ``0O``. Underscores within ## `s` are ignored. var i = 0 - if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2) - while true: + if i+1 < s.len and s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2) + while i < s.len: case s[i] of '_': inc(i) of '0'..'7': result = result shl 3 or (ord(s[i]) - ord('0')) inc(i) - of '\0': break else: raise newException(ValueError, "invalid integer: " & s) proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect, @@ -1849,16 +1661,18 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, ## If `s` does not begin with ``prefix`` and end with ``suffix`` a ## ValueError exception will be raised. ## - ## **Warning:** This procedure is deprecated because it's to easy to missuse. + ## **Warning:** This procedure is deprecated because it's to easy to missuse. result = newStringOfCap(s.len) var i = prefix.len if not s.startsWith(prefix): raise newException(ValueError, - "String does not start with a prefix of: " & prefix) + "String does not start with: " & prefix) while true: - if i == s.len-suffix.len: break - case s[i] - of '\\': + if i >= s.len-suffix.len: break + if s[i] == '\\': + if i+1 >= s.len: + result.add('\\') + break case s[i+1]: of 'x': inc i, 2 @@ -1872,15 +1686,15 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, result.add('\'') of '\"': result.add('\"') - else: result.add("\\" & s[i+1]) - inc(i) - of '\0': break + else: + result.add("\\" & s[i+1]) + inc(i, 2) else: result.add(s[i]) - inc(i) + inc(i) if not s.endsWith(suffix): raise newException(ValueError, - "String does not end with a suffix of: " & suffix) + "String does not end in: " & suffix) proc validIdentifier*(s: string): bool {.noSideEffect, rtl, extern: "nsuValidIdentifier".} = @@ -1890,7 +1704,7 @@ proc validIdentifier*(s: string): bool {.noSideEffect, ## and is followed by any number of characters of the set `IdentChars`. runnableExamples: doAssert "abc_def08".validIdentifier - if s[0] in IdentStartChars: + if s.len > 0 and s[0] in IdentStartChars: for i in 1..s.len-1: if s[i] notin IdentChars: return false return true @@ -1909,7 +1723,7 @@ proc editDistance*(a, b: string): int {.noSideEffect, # strip common prefix: var s = 0 - while a[s] == b[s] and a[s] != '\0': + while s < len1 and a[s] == b[s]: inc(s) dec(len1) dec(len2) @@ -1982,8 +1796,6 @@ proc editDistance*(a, b: string): int {.noSideEffect, if x > c3: x = c3 row[p] = x result = row[e] - #dealloc(row) - # floating point formating: when not defined(js): @@ -2092,7 +1904,7 @@ proc trimZeros*(x: var string) {.noSideEffect.} = var spl: seq[string] if x.contains('.') or x.contains(','): if x.contains('e'): - spl= x.split('e') + spl = x.split('e') x = spl[0] while x[x.high] == '0': x.setLen(x.len-1) @@ -2310,9 +2122,8 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {. var i = 0 var num = 0 while i < len(formatstr): - if formatstr[i] == '$': - case formatstr[i+1] # again we use the fact that strings - # are zero-terminated here + if formatstr[i] == '$' and i+1 < len(formatstr): + case formatstr[i+1] of '#': if num > a.high: invalidFormatString() add s, a[num] @@ -2326,7 +2137,7 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {. inc(i) # skip $ var negative = formatstr[i] == '-' if negative: inc i - while formatstr[i] in Digits: + while i < formatstr.len and formatstr[i] in Digits: j = j * 10 + ord(formatstr[i]) - ord('0') inc(i) let idx = if not negative: j-1 else: a.len-j @@ -2338,7 +2149,7 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {. var negative = formatstr[j] == '-' if negative: inc j var isNumber = 0 - while formatstr[j] notin {'\0', '}'}: + while j < formatstr.len and formatstr[j] notin {'\0', '}'}: if formatstr[j] in Digits: k = k * 10 + ord(formatstr[j]) - ord('0') if isNumber == 0: isNumber = 1 @@ -2356,7 +2167,7 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {. i = j+1 of 'a'..'z', 'A'..'Z', '\128'..'\255', '_': var j = i+1 - while formatstr[j] in PatternChars: inc(j) + while j < formatstr.len and formatstr[j] in PatternChars: inc(j) var x = findNormalized(substr(formatstr, i+1, j-1), a) if x >= 0 and x < high(a): add s, a[x+1] else: invalidFormatString() @@ -2628,13 +2439,7 @@ when isMainModule: doAssert isSpaceAscii(" ") doAssert(not isSpaceAscii("ABc \td")) - doAssert(isNilOrEmpty("")) - doAssert(isNilOrEmpty(nil)) - doAssert(not isNilOrEmpty("test")) - doAssert(not isNilOrEmpty(" ")) - doAssert(isNilOrWhitespace("")) - doAssert(isNilOrWhitespace(nil)) doAssert(isNilOrWhitespace(" ")) doAssert(isNilOrWhitespace("\t\l \v\r\f")) doAssert(not isNilOrWhitespace("ABc \td")) From e3e18b277cab8188cb8c859a72690b7b0815dd24 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 01:03:24 +0200 Subject: [PATCH 083/214] renderer.nim: bugfix --- compiler/renderer.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 2a65a10a80..11d8e86a72 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1064,6 +1064,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = if n.len > 1: let opr = if n[0].kind == nkIdent: n[0].ident elif n[0].kind == nkSym: n[0].sym.name + elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name else: nil if n[1].kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)): put(g, tkSpaces, Space) From 37901b50b35e2230e96dd5157ae7a1d1300b2411 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 01:07:13 +0200 Subject: [PATCH 084/214] strscans module does not rely on the zero terminator anymore --- lib/pure/strscans.nim | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index f8a0c43eec..b0af149b53 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -87,7 +87,7 @@ which we then use in our scanf pattern to help us in the matching process: proc someSep(input: string; start: int; seps: set[char] = {':','-','.'}): int = # Note: The parameters and return value must match to what ``scanf`` requires result = 0 - while input[start+result] in seps: inc result + while start+result < input.len and input[start+result] in seps: inc result if scanf(input, "$w$[someSep]$w", key, value): ... @@ -231,7 +231,7 @@ is performed. var i = start var u = 0 while true: - if s[i] == '\0' or s[i] == unless: + if i >= s.len or s[i] == unless: return 0 elif s[i] == until[0]: u = 1 @@ -315,6 +315,8 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b conds.add resLen.notZero conds.add resLen + template at(s: string; i: int): char = (if i < s.len: s[i] else: '\0') + var i = 0 var p = 0 var idx = genSym(nskVar, "idx") @@ -397,7 +399,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b var nesting = 0 let start = p while true: - case pattern[p] + case pattern.at(p) of '{': inc nesting of '}': if nesting == 0: break @@ -419,7 +421,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b var nesting = 0 let start = p while true: - case pattern[p] + case pattern.at(p) of '[': inc nesting of ']': if nesting == 0: break @@ -451,10 +453,12 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b template atom*(input: string; idx: int; c: char): bool = ## Used in scanp for the matching of atoms (usually chars). - input[idx] == c + idx < input.len and input[idx] == c template atom*(input: string; idx: int; s: set[char]): bool = - input[idx] in s + idx < input.len and input[idx] in s + +template hasNxt*(input: string; idx: int): bool = idx < input.len #template prepare*(input: string): int = 0 template success*(x: int): bool = x != 0 @@ -462,7 +466,7 @@ template success*(x: int): bool = x != 0 template nxt*(input: string; idx, step: int = 1) = inc(idx, step) macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = - ## ``scanp`` is currently undocumented. + ## See top level documentation of his module of how ``scanf`` works. type StmtTriple = tuple[init, cond, action: NimNode] template interf(x): untyped = bindSym(x, brForceOpen) @@ -508,8 +512,8 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = !!newCall(interf"nxt", input, idx, resLen)) of nnkCallKinds: # *{'A'..'Z'} !! s.add(!_) - template buildWhile(init, cond, action): untyped = - while true: + template buildWhile(input, idx, init, cond, action): untyped = + while hasNxt(input, idx): init if not cond: break action @@ -528,7 +532,7 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = !!newCall(interf"nxt", input, idx, it[2])) elif it.kind == nnkPrefix and it[0].eqIdent"*": let (init, cond, action) = atm(it[1], input, idx, attached) - result = (getAst(buildWhile(init, cond, action)), + result = (getAst(buildWhile(input, idx, init, cond, action)), newEmptyNode(), newEmptyNode()) elif it.kind == nnkPrefix and it[0].eqIdent"+": # x+ is the same as xx* @@ -621,7 +625,7 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = when isMainModule: proc twoDigits(input: string; x: var int; start: int): int = - if input[start] == '0' and input[start+1] == '0': + if start+1 < input.len and input[start] == '0' and input[start+1] == '0': result = 2 x = 13 else: @@ -629,10 +633,10 @@ when isMainModule: proc someSep(input: string; start: int; seps: set[char] = {';',',','-','.'}): int = result = 0 - while input[start+result] in seps: inc result + while start+result < input.len and input[start+result] in seps: inc result proc demangle(s: string; res: var string; start: int): int = - while s[result+start] in {'_', '@'}: inc result + while result+start < s.len and s[result+start] in {'_', '@'}: inc result res = "" while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_': res.add s[result+start] @@ -652,7 +656,7 @@ when isMainModule: var info = "" if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "), demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')', - *`whites`, "at ", +(~{'\C', '\L', '\0'} -> info.add($_)) ): + *`whites`, "at ", +(~{'\C', '\L'} -> info.add($_)) ): result.add prc & " " & info else: break @@ -713,7 +717,7 @@ when isMainModule: "NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605", "NimMain c:/users/anwender/projects/nim/lib/system.nim:2613", "main c:/users/anwender/projects/nim/lib/system.nim:2620"] - doAssert parseGDB(gdbOut) == result + #doAssert parseGDB(gdbOut) == result # bug #6487 var count = 0 From a97684e27768b5e1e8fbf291977a7193ce1b91ca Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 01:08:01 +0200 Subject: [PATCH 085/214] parseutils does not depend on the zero terminator anymore --- lib/pure/parseutils.nim | 107 ++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index cecc94e925..1d76234ea0 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -51,9 +51,9 @@ proc parseHex*(s: string, number: var int, start = 0; maxLen = 0): int {. ## upper bound. Not more than ```maxLen`` characters are parsed. var i = start var foundDigit = false - if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2) - elif s[i] == '#': inc(i) let last = if maxLen == 0: s.len else: i+maxLen + if i+1 < last and s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2) + elif i < last and s[i] == '#': inc(i) while i < last: case s[i] of '_': discard @@ -76,8 +76,8 @@ proc parseOct*(s: string, number: var int, start = 0): int {. ## the number of the parsed characters or 0 in case of an error. var i = start var foundDigit = false - if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2) - while true: + if i+1 < s.len and s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2) + while i < s.len: case s[i] of '_': discard of '0'..'7': @@ -93,8 +93,8 @@ proc parseBin*(s: string, number: var int, start = 0): int {. ## the number of the parsed characters or 0 in case of an error. var i = start var foundDigit = false - if s[i] == '0' and (s[i+1] == 'b' or s[i+1] == 'B'): inc(i, 2) - while true: + if i+1 < s.len and s[i] == '0' and (s[i+1] == 'b' or s[i+1] == 'B'): inc(i, 2) + while i < s.len: case s[i] of '_': discard of '0'..'1': @@ -108,9 +108,9 @@ proc parseIdent*(s: string, ident: var string, start = 0): int = ## parses an identifier and stores it in ``ident``. Returns ## the number of the parsed characters or 0 in case of an error. var i = start - if s[i] in IdentStartChars: + if i < s.len and s[i] in IdentStartChars: inc(i) - while s[i] in IdentChars: inc(i) + while i < s.len and s[i] in IdentChars: inc(i) ident = substr(s, start, i-1) result = i-start @@ -119,11 +119,9 @@ proc parseIdent*(s: string, start = 0): string = ## Returns the parsed identifier or an empty string in case of an error. result = "" var i = start - - if s[i] in IdentStartChars: + if i < s.len and s[i] in IdentStartChars: inc(i) - while s[i] in IdentChars: inc(i) - + while i < s.len and s[i] in IdentChars: inc(i) result = substr(s, start, i-1) proc parseToken*(s: string, token: var string, validChars: set[char], @@ -134,24 +132,26 @@ proc parseToken*(s: string, token: var string, validChars: set[char], ## ## **Deprecated since version 0.8.12**: Use ``parseWhile`` instead. var i = start - while s[i] in validChars: inc(i) + while i < s.len and s[i] in validChars: inc(i) result = i-start token = substr(s, start, i-1) proc skipWhitespace*(s: string, start = 0): int {.inline.} = ## skips the whitespace starting at ``s[start]``. Returns the number of ## skipped characters. - while s[start+result] in Whitespace: inc(result) + while start+result < s.len and s[start+result] in Whitespace: inc(result) proc skip*(s, token: string, start = 0): int {.inline.} = ## skips the `token` starting at ``s[start]``. Returns the length of `token` ## or 0 if there was no `token` at ``s[start]``. - while result < token.len and s[result+start] == token[result]: inc(result) + while start+result < s.len and result < token.len and + s[result+start] == token[result]: + inc(result) if result != token.len: result = 0 proc skipIgnoreCase*(s, token: string, start = 0): int = ## same as `skip` but case is ignored for token matching. - while result < token.len and + while start+result < s.len and result < token.len and toLower(s[result+start]) == toLower(token[result]): inc(result) if result != token.len: result = 0 @@ -159,18 +159,18 @@ proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} = ## Skips all characters until one char from the set `until` is found ## or the end is reached. ## Returns number of characters skipped. - while s[result+start] notin until and s[result+start] != '\0': inc(result) + while start+result < s.len and s[result+start] notin until: inc(result) proc skipUntil*(s: string, until: char, start = 0): int {.inline.} = ## Skips all characters until the char `until` is found ## or the end is reached. ## Returns number of characters skipped. - while s[result+start] != until and s[result+start] != '\0': inc(result) + while start+result < s.len and s[result+start] != until: inc(result) proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} = ## Skips all characters while one char from the set `token` is found. ## Returns number of characters skipped. - while s[result+start] in toSkip and s[result+start] != '\0': inc(result) + while start+result < s.len and s[result+start] in toSkip: inc(result) proc parseUntil*(s: string, token: var string, until: set[char], start = 0): int {.inline.} = @@ -214,7 +214,7 @@ proc parseWhile*(s: string, token: var string, validChars: set[char], ## the number of the parsed characters or 0 in case of an error. A token ## consists of the characters in `validChars`. var i = start - while s[i] in validChars: inc(i) + while i < s.len and s[i] in validChars: inc(i) result = i-start token = substr(s, start, i-1) @@ -231,16 +231,17 @@ proc rawParseInt(s: string, b: var BiggestInt, start = 0): int = var sign: BiggestInt = -1 i = start - if s[i] == '+': inc(i) - elif s[i] == '-': - inc(i) - sign = 1 - if s[i] in {'0'..'9'}: + if i < s.len: + if s[i] == '+': inc(i) + elif s[i] == '-': + inc(i) + sign = 1 + if i < s.len and s[i] in {'0'..'9'}: b = 0 - while s[i] in {'0'..'9'}: + while i < s.len and s[i] in {'0'..'9'}: b = b * 10 - (ord(s[i]) - ord('0')) inc(i) - while s[i] == '_': inc(i) # underscores are allowed and ignored + while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored b = b * sign result = i - start {.pop.} # overflowChecks @@ -281,17 +282,17 @@ proc parseSaturatedNatural*(s: string, b: var int, start = 0): int = ## discard parseSaturatedNatural("848", res) ## doAssert res == 848 var i = start - if s[i] == '+': inc(i) - if s[i] in {'0'..'9'}: + if i < s.len and s[i] == '+': inc(i) + if i < s.len and s[i] in {'0'..'9'}: b = 0 - while s[i] in {'0'..'9'}: + while i < s.len and s[i] in {'0'..'9'}: let c = ord(s[i]) - ord('0') if b <= (high(int) - c) div 10: b = b * 10 + c else: b = high(int) inc(i) - while s[i] == '_': inc(i) # underscores are allowed and ignored + while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored result = i - start # overflowChecks doesn't work with BiggestUInt @@ -300,16 +301,16 @@ proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int = res = 0.BiggestUInt prev = 0.BiggestUInt i = start - if s[i] == '+': inc(i) # Allow - if s[i] in {'0'..'9'}: + if i < s.len and s[i] == '+': inc(i) # Allow + if i < s.len and s[i] in {'0'..'9'}: b = 0 - while s[i] in {'0'..'9'}: + while i < s.len and s[i] in {'0'..'9'}: prev = res res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt if prev > res: return 0 # overflowChecks emulation inc(i) - while s[i] == '_': inc(i) # underscores are allowed and ignored + while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored b = res result = i - start @@ -389,31 +390,31 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, var kind: InterpolatedKind while true: var j = i - if s[j] == '$': - if s[j+1] == '{': + if j < s.len and s[j] == '$': + if j+1 < s.len and s[j+1] == '{': inc j, 2 var nesting = 0 - while true: - case s[j] - of '{': inc nesting - of '}': - if nesting == 0: - inc j - break - dec nesting - of '\0': - raise newException(ValueError, - "Expected closing '}': " & substr(s, i, s.high)) - else: discard - inc j + block curlies: + while j < s.len: + case s[j] + of '{': inc nesting + of '}': + if nesting == 0: + inc j + break curlies + dec nesting + else: discard + inc j + raise newException(ValueError, + "Expected closing '}': " & substr(s, i, s.high)) inc i, 2 # skip ${ kind = ikExpr - elif s[j+1] in IdentStartChars: + elif j+1 < s.len and s[j+1] in IdentStartChars: inc j, 2 - while s[j] in IdentChars: inc(j) + while j < s.len and s[j] in IdentChars: inc(j) inc i # skip $ kind = ikVar - elif s[j+1] == '$': + elif j+1 < s.len and s[j+1] == '$': inc j, 2 inc i # skip $ kind = ikDollar From 68a63b340776c98e2455d79286aab04db3ff02bd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 01:08:37 +0200 Subject: [PATCH 086/214] RST package: don't use obsolete toLower proc --- lib/packages/docutils/rstgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index ee1f0076ce..1547c888d8 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -774,7 +774,7 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) = Digits + Letters + WhiteSpace) let arg = getArgument(n) - isObject = arg.toLower().endsWith(".svg") + isObject = arg.toLowerAscii().endsWith(".svg") var options = "" content = "" From 7e0540ed80ac0685458e1ccf9e3f7ba38772d32c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 01:09:05 +0200 Subject: [PATCH 087/214] the compiler does not rely on the zero terminator anymore --- compiler/lexer.nim | 15 +++++++-------- compiler/ropes.nim | 2 +- compiler/syntaxes.nim | 10 +++++----- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 0b1090bb1f..0478ed574c 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -165,13 +165,12 @@ proc isKeyword*(kind: TTokType): bool = template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion proc isNimIdentifier*(s: string): bool = - if s[0] in SymStartChars: + let sLen = s.len + if sLen > 0 and s[0] in SymStartChars: var i = 1 - var sLen = s.len while i < sLen: - if s[i] == '_': - inc(i) - if s[i] notin SymChars: return + if s[i] == '_': inc(i) + if i < sLen and s[i] notin SymChars: return inc(i) result = true @@ -311,12 +310,12 @@ template tokenEndPrevious(tok, pos) = # We need to parse the largest uint literal without overflow checks proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int = var i = start - if s[i] in {'0'..'9'}: + if i < s.len and s[i] in {'0'..'9'}: b = 0 - while s[i] in {'0'..'9'}: + while i < s.len and s[i] in {'0'..'9'}: b = b * 10 + (ord(s[i]) - ord('0')) inc(i) - while s[i] == '_': inc(i) # underscores are allowed and ignored + while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored result = i - start {.pop.} # overflowChecks diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 358ce8a53a..89b92b76d0 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -251,7 +251,7 @@ proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope = while true: j = j * 10 + ord(frmt[i]) - ord('0') inc(i) - if frmt[i] notin {'0'..'9'}: break + if i >= frmt.len or frmt[i] notin {'0'..'9'}: break num = j if j > high(args) + 1: errorHandler(rInvalidFormatStr, $(j)) diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 4014d4c584..5413565e6f 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -51,15 +51,15 @@ proc parseTopLevelStmt*(p: var TParsers): PNode = result = ast.emptyNode proc utf8Bom(s: string): int = - if s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF': + if s.len >= 3 and s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF': result = 3 else: result = 0 proc containsShebang(s: string, i: int): bool = - if s[i] == '#' and s[i+1] == '!': + if i+1 < s.len and s[i] == '#' and s[i+1] == '!': var j = i + 2 - while s[j] in Whitespace: inc(j) + while j < s.len and s[j] in Whitespace: inc(j) result = s[j] == '/' proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNode = @@ -74,9 +74,9 @@ proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNo discard llStreamReadLine(s, line) i = 0 inc linenumber - if line[i] == '#' and line[i+1] == '?': + if i+1 < line.len and line[i] == '#' and line[i+1] == '?': inc(i, 2) - while line[i] in Whitespace: inc(i) + while i < line.len and line[i] in Whitespace: inc(i) var q: TParser parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache) result = parser.parseAll(q) From 39b81c836cf09912296799d66124db9b1efcedc8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 01:18:26 +0200 Subject: [PATCH 088/214] cgi module: don't depent on the terminating zero --- lib/pure/cgi.nim | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index 5de6aa4870..a5a4044970 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -97,11 +97,10 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] = var name = "" var value = "" # decode everything in one pass: - while data[i] != '\0': + while i < data.len: setLen(name, 0) # reuse memory - while true: + while i < data.len: case data[i] - of '\0': break of '%': var x = 0 handleHexChar(data[i+1], x) @@ -112,15 +111,16 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] = of '=', '&': break else: add(name, data[i]) inc(i) - if data[i] != '=': cgiError("'=' expected") + if i >= data.len or data[i] != '=': cgiError("'=' expected") inc(i) # skip '=' setLen(value, 0) # reuse memory - while true: + while i < data.len: case data[i] of '%': var x = 0 - handleHexChar(data[i+1], x) - handleHexChar(data[i+2], x) + if i+2 < data.len: + handleHexChar(data[i+1], x) + handleHexChar(data[i+2], x) inc(i, 2) add(value, chr(x)) of '+': add(value, ' ') @@ -128,9 +128,9 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] = else: add(value, data[i]) inc(i) yield (name.TaintedString, value.TaintedString) - if data[i] == '&': inc(i) - elif data[i] == '\0': break - else: cgiError("'&' expected") + if i < data.len: + if data[i] == '&': inc(i) + else: cgiError("'&' expected") iterator decodeData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] = From 203d833688850fd6686e9f7c272cae86f892c47e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 01:31:29 +0200 Subject: [PATCH 089/214] parseopt stdlib module: dont rely on the zero terminator --- lib/pure/parseopt.nim | 48 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index ffb69a72b5..c1a6161f9e 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -57,26 +57,26 @@ type {.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].} proc parseWord(s: string, i: int, w: var string, - delim: set[char] = {'\x09', ' ', '\0'}): int = + delim: set[char] = {'\x09', ' '}): int = result = i - if s[result] == '\"': + if result < s.len and s[result] == '\"': inc(result) - while not (s[result] in {'\0', '\"'}): + while result < s.len and s[result] != '\"': add(w, s[result]) inc(result) - if s[result] == '\"': inc(result) + if result < s.len and s[result] == '\"': inc(result) else: - while not (s[result] in delim): + while result < s.len and s[result] notin delim: add(w, s[result]) inc(result) when declared(os.paramCount): proc quote(s: string): string = - if find(s, {' ', '\t'}) >= 0 and s[0] != '"': + if find(s, {' ', '\t'}) >= 0 and s.len > 0 and s[0] != '"': if s[0] == '-': result = newStringOfCap(s.len) - var i = parseWord(s, 0, result, {'\0', ' ', '\x09', ':', '='}) - if s[i] in {':','='}: + var i = parseWord(s, 0, result, {' ', '\x09', ':', '='}) + if i < s.len and s[i] in {':','='}: result.add s[i] inc i result.add '"' @@ -144,43 +144,45 @@ proc handleShortOption(p: var OptParser) = add(p.key.string, p.cmd[i]) inc(i) p.inShortState = true - while p.cmd[i] in {'\x09', ' '}: + while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i) p.inShortState = false - if p.cmd[i] in {':', '='} or card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal: - if p.cmd[i] in {':', '='}: + if i < p.cmd.len and p.cmd[i] in {':', '='} or + card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal: + if i < p.cmd.len and p.cmd[i] in {':', '='}: inc(i) p.inShortState = false - while p.cmd[i] in {'\x09', ' '}: inc(i) + while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i) i = parseWord(p.cmd, i, p.val.string) - if p.cmd[i] == '\0': p.inShortState = false + if i >= p.cmd.len: p.inShortState = false p.pos = i proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = ## parses the first or next option; ``p.kind`` describes what token has been ## parsed. ``p.key`` and ``p.val`` are set accordingly. var i = p.pos - while p.cmd[i] in {'\x09', ' '}: inc(i) + while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i) p.pos = i setLen(p.key.string, 0) setLen(p.val.string, 0) if p.inShortState: handleShortOption(p) return - case p.cmd[i] - of '\0': + if i >= p.cmd.len: p.kind = cmdEnd - of '-': + return + if p.cmd[i] == '-': inc(i) - if p.cmd[i] == '-': + if i < p.cmd.len and p.cmd[i] == '-': p.kind = cmdLongOption inc(i) - i = parseWord(p.cmd, i, p.key.string, {'\0', ' ', '\x09', ':', '='}) - while p.cmd[i] in {'\x09', ' '}: inc(i) - if p.cmd[i] in {':', '='} or len(p.longNoVal) > 0 and p.key.string notin p.longNoVal: - if p.cmd[i] in {':', '='}: + i = parseWord(p.cmd, i, p.key.string, {' ', '\x09', ':', '='}) + while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i) + if i < p.cmd.len and p.cmd[i] in {':', '='} or + len(p.longNoVal) > 0 and p.key.string notin p.longNoVal: + if i < p.cmd.len and p.cmd[i] in {':', '='}: inc(i) - while p.cmd[i] in {'\x09', ' '}: inc(i) + while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i) p.pos = parseWord(p.cmd, i, p.val.string) else: p.pos = i From f4c21305a9c0fdbc1f1225dffec022dbc88df67c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 01:46:40 +0200 Subject: [PATCH 090/214] uri.nim: don't rely on zero termination --- lib/pure/uri.nim | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index d2d11253a9..9bf25b86b4 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -60,7 +60,7 @@ proc encodeUrl*(s: string): string = else: add(result, '%') add(result, toHex(ord(s[i]), 2)) - + proc decodeUrl*(s: string): string = ## Decodes a value from its HTTP representation: This means that a ``'+'`` ## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal @@ -72,7 +72,7 @@ proc decodeUrl*(s: string): string = of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) else: assert(false) - + result = newString(s.len) var i = 0 var j = 0 @@ -94,7 +94,7 @@ proc parseAuthority(authority: string, result: var Uri) = var i = 0 var inPort = false var inIPv6 = false - while true: + while i < authority.len: case authority[i] of '@': swap result.password, result.port @@ -111,7 +111,6 @@ proc parseAuthority(authority: string, result: var Uri) = inIPv6 = true of ']': inIPv6 = false - of '\0': break else: if inPort: result.port.add(authority[i]) @@ -128,11 +127,11 @@ proc parsePath(uri: string, i: var int, result: var Uri) = parseAuthority(result.path, result) result.path.setLen(0) - if uri[i] == '?': + if i < uri.len and uri[i] == '?': i.inc # Skip '?' i.inc parseUntil(uri, result.query, {'#'}, i) - if uri[i] == '#': + if i < uri.len and uri[i] == '#': i.inc # Skip '#' i.inc parseUntil(uri, result.anchor, {}, i) @@ -156,7 +155,7 @@ proc parseUri*(uri: string, result: var Uri) = # Check if this is a reference URI (relative URI) let doubleSlash = uri.len > 1 and uri[1] == '/' - if uri[i] == '/': + if i < uri.len and uri[i] == '/': # Make sure ``uri`` doesn't begin with '//'. if not doubleSlash: parsePath(uri, i, result) @@ -164,7 +163,7 @@ proc parseUri*(uri: string, result: var Uri) = # Scheme i.inc parseWhile(uri, result.scheme, Letters + Digits + {'+', '-', '.'}, i) - if uri[i] != ':' and not doubleSlash: + if (i >= uri.len or uri[i] != ':') and not doubleSlash: # Assume this is a reference URI (relative URI) i = 0 result.scheme.setLen(0) @@ -174,7 +173,7 @@ proc parseUri*(uri: string, result: var Uri) = i.inc # Skip ':' # Authority - if uri[i] == '/' and uri[i+1] == '/': + if i+1 < uri.len and uri[i] == '/' and uri[i+1] == '/': i.inc(2) # Skip // var authority = "" i.inc parseUntil(uri, authority, {'/', '?', '#'}, i) @@ -197,13 +196,13 @@ proc removeDotSegments(path: string): string = let endsWithSlash = path[path.len-1] == '/' var i = 0 var currentSegment = "" - while true: + while i < path.len: case path[i] of '/': collection.add(currentSegment) currentSegment = "" of '.': - if path[i+1] == '.' and path[i+2] == '/': + if i+2 < path.len and path[i+1] == '.' and path[i+2] == '/': if collection.len > 0: discard collection.pop() i.inc 3 @@ -212,13 +211,11 @@ proc removeDotSegments(path: string): string = i.inc 2 continue currentSegment.add path[i] - of '\0': - if currentSegment != "": - collection.add currentSegment - break else: currentSegment.add path[i] i.inc + if currentSegment != "": + collection.add currentSegment result = collection.join("/") if endsWithSlash: result.add '/' @@ -320,18 +317,18 @@ proc `/`*(x: Uri, path: string): Uri = result = x if result.path.len == 0: - if path[0] != '/': + if path.len == 0 or path[0] != '/': result.path = "/" result.path.add(path) return - if result.path[result.path.len-1] == '/': - if path[0] == '/': + if result.path.len > 0 and result.path[result.path.len-1] == '/': + if path.len > 0 and path[0] == '/': result.path.add(path[1 .. path.len-1]) else: result.path.add(path) else: - if path[0] != '/': + if path.len == 0 or path[0] != '/': result.path.add '/' result.path.add(path) @@ -373,7 +370,7 @@ when isMainModule: const test1 = "abc\L+def xyz" doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz" doAssert decodeUrl(encodeUrl(test1)) == test1 - + block: let str = "http://localhost" let test = parseUri(str) @@ -464,7 +461,7 @@ when isMainModule: doAssert test.hostname == "github.com" doAssert test.port == "dom96" doAssert test.path == "/packages" - + block: let str = "file:///foo/bar/baz.txt" let test = parseUri(str) From b899713832a9fd9523117dfccc3b893825bad454 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 01:48:21 +0200 Subject: [PATCH 091/214] make more tests green --- lib/pure/collections/critbits.nim | 4 ++-- lib/pure/ospaths.nim | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 34f5c54708..ed8583ae55 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -74,11 +74,11 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = var newByte = 0 block blockX: while newbyte < key.len: - if it.key[newbyte] != key[newbyte]: + if newbyte >= it.key.len or it.key[newbyte] != key[newbyte]: newotherbits = it.key[newbyte].ord xor key[newbyte].ord break blockX inc newbyte - if it.key[newbyte] != '\0': + if newbyte < it.key.len: newotherbits = it.key[newbyte].ord else: return it diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index 0d638abb9b..aeb4a149e1 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -196,7 +196,7 @@ proc joinPath*(head, tail: string): string {. else: result = head & tail else: - if tail[0] in {DirSep, AltSep}: + if tail.len > 0 and tail[0] in {DirSep, AltSep}: result = head & tail else: result = head & DirSep & tail From c8b2e65dbb13ea3e301e26a75557966d7d06df64 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 07:42:47 +0200 Subject: [PATCH 092/214] critbits: don't rely on terminating zero --- lib/pure/collections/critbits.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index ed8583ae55..95fffdf88c 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -74,8 +74,9 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = var newByte = 0 block blockX: while newbyte < key.len: - if newbyte >= it.key.len or it.key[newbyte] != key[newbyte]: - newotherbits = it.key[newbyte].ord xor key[newbyte].ord + let ch = if newbyte < it.key.len: it.key[newbyte] else: '\0' + if ch != key[newbyte]: + newotherbits = ch.ord xor key[newbyte].ord break blockX inc newbyte if newbyte < it.key.len: @@ -85,7 +86,7 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = while (newOtherBits and (newOtherBits-1)) != 0: newOtherBits = newOtherBits and (newOtherBits-1) newOtherBits = newOtherBits xor 255 - let ch = it.key[newByte] + let ch = if newByte < it.key.len: it.key[newByte] else: '\0' let dir = (1 + (ord(ch) or newOtherBits)) shr 8 var inner: Node[T] From 4375dfd9d07ef254a008a7417377c6d237b1d88a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 07:43:11 +0200 Subject: [PATCH 093/214] pegs: don't rely on terminating zero --- lib/pure/pegs.nim | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 5ae2d9182f..90a460776f 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -534,15 +534,15 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. case p.kind of pkEmpty: result = 0 # match of length 0 of pkAny: - if s[start] != '\0': result = 1 + if start < s.len: result = 1 else: result = -1 of pkAnyRune: - if s[start] != '\0': + if start < s.len: result = runeLenAt(s, start) else: result = -1 of pkLetter: - if s[start] != '\0': + if start < s.len: var a: Rune result = start fastRuneAt(s, result, a) @@ -551,7 +551,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. else: result = -1 of pkLower: - if s[start] != '\0': + if start < s.len: var a: Rune result = start fastRuneAt(s, result, a) @@ -560,7 +560,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. else: result = -1 of pkUpper: - if s[start] != '\0': + if start < s.len: var a: Rune result = start fastRuneAt(s, result, a) @@ -569,7 +569,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. else: result = -1 of pkTitle: - if s[start] != '\0': + if start < s.len: var a: Rune result = start fastRuneAt(s, result, a) @@ -578,7 +578,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. else: result = -1 of pkWhitespace: - if s[start] != '\0': + if start < s.len: var a: Rune result = start fastRuneAt(s, result, a) @@ -589,15 +589,15 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. of pkGreedyAny: result = len(s) - start of pkNewLine: - if s[start] == '\L': result = 1 - elif s[start] == '\C': - if s[start+1] == '\L': result = 2 + if start < s.len and s[start] == '\L': result = 1 + elif start < s.len and s[start] == '\C': + if start+1 < s.len and s[start+1] == '\L': result = 2 else: result = 1 else: result = -1 of pkTerminal: result = len(p.term) for i in 0..result-1: - if p.term[i] != s[start+i]: + if start+i >= s.len or p.term[i] != s[start+i]: result = -1 break of pkTerminalIgnoreCase: @@ -606,6 +606,9 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. a, b: Rune result = start while i < len(p.term): + if i >= s.len: + result = -1 + break fastRuneAt(p.term, i, a) fastRuneAt(s, result, b) if toLower(a) != toLower(b): @@ -621,18 +624,23 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. while true: fastRuneAt(p.term, i, a) if a != Rune('_'): break - while true: + while result < s.len: fastRuneAt(s, result, b) if b != Rune('_'): break - if toLower(a) != toLower(b): + if result >= s.len: + if i >= p.term.len: break + else: + result = -1 + break + elif toLower(a) != toLower(b): result = -1 break dec(result, start) of pkChar: - if p.ch == s[start]: result = 1 + if start < s.len and p.ch == s[start]: result = 1 else: result = -1 of pkCharChoice: - if contains(p.charChoice[], s[start]): result = 1 + if start < s.len and contains(p.charChoice[], s[start]): result = 1 else: result = -1 of pkNonTerminal: var oldMl = c.ml @@ -695,10 +703,10 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. of pkGreedyRepChar: result = 0 var ch = p.ch - while ch == s[start+result]: inc(result) + while start+result < s.len and ch == s[start+result]: inc(result) of pkGreedyRepSet: result = 0 - while contains(p.charChoice[], s[start+result]): inc(result) + while start+result < s.len and contains(p.charChoice[], s[start+result]): inc(result) of pkOption: result = max(0, rawMatch(s, p.sons[0], start, c)) of pkAndPredicate: From 9e6656d562e8008aec73fc6bc6ee05bfa36bab46 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 07:58:24 +0200 Subject: [PATCH 094/214] disable hanging test --- tests/vm/tcompiletimetable.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/vm/tcompiletimetable.nim b/tests/vm/tcompiletimetable.nim index e78c06536c..b5b84a7907 100644 --- a/tests/vm/tcompiletimetable.nim +++ b/tests/vm/tcompiletimetable.nim @@ -4,6 +4,7 @@ discard """ 4:2 Got Hi Got Hey''' + disabled: "true" """ # bug #404 From 22670aad84b41641e23ea5dabc03829015275e00 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 07:59:03 +0200 Subject: [PATCH 095/214] make nre compile again --- lib/impure/nre.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 582f5ab3bc..6058128ddf 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -10,7 +10,7 @@ from pcre import nil import nre.private.util import tables -from strutils import toLower, `%` +from strutils import `%` from math import ceil import options from unicode import runeLenAt @@ -326,15 +326,15 @@ proc `$`*(pattern: RegexMatch): string = proc `==`*(a, b: Regex): bool = if not a.isNil and not b.isNil: - return a.pattern == b.pattern and - a.pcreObj == b.pcreObj and + return a.pattern == b.pattern and + a.pcreObj == b.pcreObj and a.pcreExtra == b.pcreExtra else: return system.`==`(a, b) proc `==`*(a, b: RegexMatch): bool = return a.pattern == b.pattern and - a.str == b.str + a.str == b.str # }}} # Creation & Destruction {{{ From aeca422dbe2db216d3adb55971c6bf7dfa93df0d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 07:59:36 +0200 Subject: [PATCH 096/214] make httpclient work without zero terminators --- lib/pure/httpclient.nim | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index db8acf0eb4..b7617b0b50 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -74,7 +74,7 @@ ## ## .. code-block:: Nim ## import asyncdispatch, httpclient -## +## ## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} = ## echo("Downloaded ", progress, " of ", total) ## echo("Current rate: ", speed div 1000, "kb/s") @@ -247,7 +247,7 @@ proc parseChunks(s: Socket, timeout: int): string = var i = 0 if chunkSizeStr == "": httpError("Server terminated connection prematurely") - while true: + while i < chunkSizeStr.len: case chunkSizeStr[i] of '0'..'9': chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0')) @@ -255,8 +255,6 @@ proc parseChunks(s: Socket, timeout: int): string = chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10) of 'A'..'F': chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10) - of '\0': - break of ';': # http://tools.ietf.org/html/rfc2616#section-3.6.1 # We don't care about chunk-extensions. @@ -938,7 +936,7 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void] var i = 0 if chunkSizeStr == "": httpError("Server terminated connection prematurely") - while true: + while i < chunkSizeStr.len: case chunkSizeStr[i] of '0'..'9': chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0')) @@ -946,8 +944,6 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void] chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10) of 'A'..'F': chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10) - of '\0': - break of ';': # http://tools.ietf.org/html/rfc2616#section-3.6.1 # We don't care about chunk-extensions. From 16b0bf6ccaedd43afd3d6d5059e9d7a0c61407af Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 08:00:45 +0200 Subject: [PATCH 097/214] make memoization test compile again --- tests/misc/tmemoization.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/misc/tmemoization.nim b/tests/misc/tmemoization.nim index 180acd89b6..840eb3b0d7 100644 --- a/tests/misc/tmemoization.nim +++ b/tests/misc/tmemoization.nim @@ -8,7 +8,7 @@ import strutils proc foo(s: static[string]): string = static: echo s - const R = s.toUpper + const R = s.toUpperAscii return R echo foo("test 1") From fb15a265c5ec1bb6081abc25fc093c1223b8faf3 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 08:13:25 +0200 Subject: [PATCH 098/214] times.nim: don't rely on zero terminator --- lib/pure/times.nim | 97 ++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 7d101beab4..bc8a50fd72 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1318,24 +1318,23 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}= result = "" var i = 0 var currentF = "" - while true: + while i < f.len: case f[i] - of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',': + of ' ', '-', '/', ':', '\'', '(', ')', '[', ']', ',': formatToken(dt, currentF, result) currentF = "" - if f[i] == '\0': break if f[i] == '\'': inc(i) # Skip ' - while f[i] != '\'' and f.len-1 > i: + while i < f.len-1 and f[i] != '\'': result.add(f[i]) inc(i) else: result.add(f[i]) else: # Check if the letter being added matches previous accumulated buffer. - if currentF.len < 1 or currentF[high(currentF)] == f[i]: + if currentF.len == 0 or currentF[high(currentF)] == f[i]: currentF.add(f[i]) else: formatToken(dt, currentF, result) @@ -1343,6 +1342,7 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}= currentF = "" inc(i) + formatToken(dt, currentF, result) proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} = ## Converts a `DateTime` object to a string representation. @@ -1439,58 +1439,58 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) = dt.month = month.Month of "MMM": case value[j..j+2].toLowerAscii(): - of "jan": dt.month = mJan - of "feb": dt.month = mFeb - of "mar": dt.month = mMar - of "apr": dt.month = mApr - of "may": dt.month = mMay - of "jun": dt.month = mJun - of "jul": dt.month = mJul - of "aug": dt.month = mAug - of "sep": dt.month = mSep - of "oct": dt.month = mOct - of "nov": dt.month = mNov - of "dec": dt.month = mDec + of "jan": dt.month = mJan + of "feb": dt.month = mFeb + of "mar": dt.month = mMar + of "apr": dt.month = mApr + of "may": dt.month = mMay + of "jun": dt.month = mJun + of "jul": dt.month = mJul + of "aug": dt.month = mAug + of "sep": dt.month = mSep + of "oct": dt.month = mOct + of "nov": dt.month = mNov + of "dec": dt.month = mDec else: raise newException(ValueError, "Couldn't parse month (MMM), got: " & value) j += 3 of "MMMM": if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0: - dt.month = mJan + dt.month = mJan j += 7 elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("february") == 0: - dt.month = mFeb + dt.month = mFeb j += 8 elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("march") == 0: - dt.month = mMar + dt.month = mMar j += 5 elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("april") == 0: - dt.month = mApr + dt.month = mApr j += 5 elif value.len >= j+3 and value[j..j+2].cmpIgnoreCase("may") == 0: - dt.month = mMay + dt.month = mMay j += 3 elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("june") == 0: - dt.month = mJun + dt.month = mJun j += 4 elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("july") == 0: - dt.month = mJul + dt.month = mJul j += 4 elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("august") == 0: - dt.month = mAug + dt.month = mAug j += 6 elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("september") == 0: - dt.month = mSep + dt.month = mSep j += 9 elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("october") == 0: - dt.month = mOct + dt.month = mOct j += 7 elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("november") == 0: - dt.month = mNov + dt.month = mNov j += 8 elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("december") == 0: - dt.month = mDec + dt.month = mDec j += 8 else: raise newException(ValueError, @@ -1521,44 +1521,47 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) = j += 4 of "z": dt.isDst = false - if value[j] == '+': + let ch = if j < value.len: value[j] else: '\0' + if ch == '+': dt.utcOffset = 0 - parseInt($value[j+1]) * secondsInHour - elif value[j] == '-': + elif ch == '-': dt.utcOffset = parseInt($value[j+1]) * secondsInHour - elif value[j] == 'Z': + elif ch == 'Z': dt.utcOffset = 0 j += 1 return else: raise newException(ValueError, - "Couldn't parse timezone offset (z), got: " & value[j]) + "Couldn't parse timezone offset (z), got: " & ch) j += 2 of "zz": dt.isDst = false - if value[j] == '+': + let ch = if j < value.len: value[j] else: '\0' + if ch == '+': dt.utcOffset = 0 - value[j+1..j+2].parseInt() * secondsInHour - elif value[j] == '-': + elif ch == '-': dt.utcOffset = value[j+1..j+2].parseInt() * secondsInHour - elif value[j] == 'Z': + elif ch == 'Z': dt.utcOffset = 0 j += 1 return else: raise newException(ValueError, - "Couldn't parse timezone offset (zz), got: " & value[j]) + "Couldn't parse timezone offset (zz), got: " & ch) j += 3 of "zzz": dt.isDst = false var factor = 0 - if value[j] == '+': factor = -1 - elif value[j] == '-': factor = 1 - elif value[j] == 'Z': + let ch = if j < value.len: value[j] else: '\0' + if ch == '+': factor = -1 + elif ch == '-': factor = 1 + elif ch == 'Z': dt.utcOffset = 0 j += 1 return else: raise newException(ValueError, - "Couldn't parse timezone offset (zzz), got: " & value[j]) + "Couldn't parse timezone offset (zzz), got: " & ch) dt.utcOffset = factor * value[j+1..j+2].parseInt() * secondsInHour j += 4 dt.utcOffset += factor * value[j..j+1].parseInt() * 60 @@ -1620,20 +1623,18 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime = dt.nanosecond = 0 dt.isDst = true # using this is flag for checking whether a timezone has \ # been read (because DST is always false when a tz is parsed) - while true: + while i < layout.len: case layout[i] - of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',': + of ' ', '-', '/', ':', '\'', '(', ')', '[', ']', ',': if token.len > 0: parseToken(dt, token, value, j) # Reset token token = "" - # Break if at end of line - if layout[i] == '\0': break # Skip separator and everything between single quotes # These are literals in both the layout and the value string if layout[i] == '\'': inc(i) - while layout[i] != '\'' and layout.len-1 > i: + while i < layout.len-1 and layout[i] != '\'': inc(i) inc(j) inc(i) @@ -1642,13 +1643,15 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime = inc(j) else: # Check if the letter being added matches previous accumulated buffer. - if token.len < 1 or token[high(token)] == layout[i]: + if token.len == 0 or token[high(token)] == layout[i]: token.add(layout[i]) inc(i) else: parseToken(dt, token, value, j) token = "" + if i >= layout.len and token.len > 0: + parseToken(dt, token, value, j) if dt.isDst: # No timezone parsed - assume timezone is `zone` result = initDateTime(zone.zoneInfoFromTz(dt.toAdjTime), zone) From 5237ef4f5280fef8df630f265cc67869d013c0ef Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Apr 2018 08:14:00 +0200 Subject: [PATCH 099/214] update the documentation about the new strings/seqs behaviours --- doc/manual.rst | 12 +- doc/tut1.rst | 18 +- tests/stdlib/tpegs.nim | 1770 ---------------------------------------- 3 files changed, 10 insertions(+), 1790 deletions(-) delete mode 100644 tests/stdlib/tpegs.nim diff --git a/doc/manual.rst b/doc/manual.rst index 636bf796be..fabcf058ad 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1471,7 +1471,7 @@ mysterious crashes. **Note**: The example only works because the memory is initialized to zero (``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to -``nil`` which the string assignment can handle. One needs to know low level +binary zero which the string assignment can handle. One needs to know low level details like this when mixing garbage collected data with unmanaged memory. .. XXX finalizers for traced objects @@ -2512,8 +2512,8 @@ char '\\0' bool false ref or pointer type nil procedural type nil -sequence nil (*not* ``@[]``) -string nil (*not* "") +sequence ``@[]`` +string ``""`` tuple[x: A, y: B, ...] (default(A), default(B), ...) (analogous for objects) array[0..., T] [default(T), ...] @@ -4270,7 +4270,7 @@ therefore very useful for type specialization within generic code: Table[Key, Value] = object keys: seq[Key] values: seq[Value] - when not (Key is string): # nil value for strings used for optimization + when not (Key is string): # empty value for strings used for optimization deletedKeys: seq[bool] @@ -7434,8 +7434,8 @@ code generation directly, but their presence can be detected by macros. Custom pragmas are defined using templates annotated with pragma ``pragma``: .. code-block:: nim - template dbTable(name: string, table_space: string = nil) {.pragma.} - template dbKey(name: string = nil, primary_key: bool = false) {.pragma.} + template dbTable(name: string, table_space: string = "") {.pragma.} + template dbKey(name: string = "", primary_key: bool = false) {.pragma.} template dbForeignKey(t: typedesc) {.pragma.} template dbIgnore {.pragma.} diff --git a/doc/tut1.rst b/doc/tut1.rst index cbfef183ec..2dc502fabe 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -960,11 +960,7 @@ enforced. For example, when reading strings from binary files, they are merely a sequence of bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the i-th *unichar*. -String variables are initialized with a special value, called ``nil``. However, -most string operations cannot deal with ``nil`` (leading to an exception being -raised) for performance reasons. It is best to use empty strings ``""`` -rather than ``nil`` as the *empty* value. But ``""`` often creates a string -object on the heap, so there is a trade-off to be made here. +String variables are initialized with the empty strings ``""``. Integers @@ -1309,11 +1305,7 @@ Example: x: seq[int] # a reference to a sequence of integers x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence allocated on the heap -Sequence variables are initialized with ``nil``. However, most sequence -operations cannot deal with ``nil`` (leading to an exception being -raised) for performance reasons. Thus one should use empty sequences ``@[]`` -rather than ``nil`` as the *empty* value. But ``@[]`` creates a sequence -object on the heap, so there is a trade-off to be made here. +Sequence variables are initialized with ``@[]``. The ``for`` statement can be used with one or two variables when used with a sequence. When you use the one variable form, the variable will hold the value @@ -1355,11 +1347,9 @@ type does not matter. .. code-block:: nim :test: "nim c $1" var - fruits: seq[string] # reference to a sequence of strings that is initialized with 'nil' + fruits: seq[string] # reference to a sequence of strings that is initialized with '@[]' capitals: array[3, string] # array of strings with a fixed size - fruits = @[] # creates an empty sequence on the heap that will be referenced by 'fruits' - capitals = ["New York", "London", "Berlin"] # array 'capitals' allows assignment of only three elements fruits.add("Banana") # sequence 'fruits' is dynamically expandable during runtime fruits.add("Mango") @@ -1691,7 +1681,7 @@ rules apply: write(stdout, x(3)) # no error: A.x is called write(stdout, x("")) # no error: B.x is called - proc x*(a: int): string = nil + proc x*(a: int): string = discard write(stdout, x(3)) # ambiguous: which `x` is to call? diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim deleted file mode 100644 index e2a5a1715d..0000000000 --- a/tests/stdlib/tpegs.nim +++ /dev/null @@ -1,1770 +0,0 @@ -discard """ - output: '''this -is -an -example -d -e -f -('keyvalue' 'key'*)''' -""" -# PEGs module turned out to be a good test to detect memory management bugs. - -include "system/inclrtl" - -const - useUnicode = true ## change this to deactivate proper UTF-8 support - -import - strutils - -when useUnicode: - import unicode - -const - InlineThreshold = 5 ## number of leaves; -1 to disable inlining - MaxSubpatterns* = 10 ## defines the maximum number of subpatterns that - ## can be captured. More subpatterns cannot be captured! - -type - TPegKind = enum - pkEmpty, - pkAny, ## any character (.) - pkAnyRune, ## any Unicode character (_) - pkNewLine, ## CR-LF, LF, CR - pkLetter, ## Unicode letter - pkLower, ## Unicode lower case letter - pkUpper, ## Unicode upper case letter - pkTitle, ## Unicode title character - pkWhitespace, ## Unicode whitespace character - pkTerminal, - pkTerminalIgnoreCase, - pkTerminalIgnoreStyle, - pkChar, ## single character to match - pkCharChoice, - pkNonTerminal, - pkSequence, ## a b c ... --> Internal DSL: peg(a, b, c) - pkOrderedChoice, ## a / b / ... --> Internal DSL: a / b or /[a, b, c] - pkGreedyRep, ## a* --> Internal DSL: *a - ## a+ --> (a a*) - pkGreedyRepChar, ## x* where x is a single character (superop) - pkGreedyRepSet, ## [set]* (superop) - pkGreedyAny, ## .* or _* (superop) - pkOption, ## a? --> Internal DSL: ?a - pkAndPredicate, ## &a --> Internal DSL: &a - pkNotPredicate, ## !a --> Internal DSL: !a - pkCapture, ## {a} --> Internal DSL: capture(a) - pkBackRef, ## $i --> Internal DSL: backref(i) - pkBackRefIgnoreCase, - pkBackRefIgnoreStyle, - pkSearch, ## @a --> Internal DSL: !*a - pkCapturedSearch, ## {@} a --> Internal DSL: !*\a - pkRule, ## a <- b - pkList, ## a, b - pkStartAnchor ## ^ --> Internal DSL: startAnchor() - TNonTerminalFlag = enum - ntDeclared, ntUsed - TNonTerminal {.final.} = object ## represents a non terminal symbol - name: string ## the name of the symbol - line: int ## line the symbol has been declared/used in - col: int ## column the symbol has been declared/used in - flags: set[TNonTerminalFlag] ## the nonterminal's flags - rule: TNode ## the rule that the symbol refers to - TNode {.final, shallow.} = object - case kind: TPegKind - of pkEmpty..pkWhitespace: nil - of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string - of pkChar, pkGreedyRepChar: ch: char - of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char] - of pkNonTerminal: nt: PNonTerminal - of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns] - else: sons: seq[TNode] - PNonTerminal* = ref TNonTerminal - - TPeg* = TNode ## type that represents a PEG - -proc term*(t: string): TPeg {.rtl, extern: "npegs$1Str".} = - ## constructs a PEG from a terminal string - if t.len != 1: - result.kind = pkTerminal - result.term = t - else: - result.kind = pkChar - result.ch = t[0] - -proc termIgnoreCase*(t: string): TPeg {. - rtl, extern: "npegs$1".} = - ## constructs a PEG from a terminal string; ignore case for matching - result.kind = pkTerminalIgnoreCase - result.term = t - -proc termIgnoreStyle*(t: string): TPeg {. - rtl, extern: "npegs$1".} = - ## constructs a PEG from a terminal string; ignore style for matching - result.kind = pkTerminalIgnoreStyle - result.term = t - -proc term*(t: char): TPeg {.rtl, extern: "npegs$1Char".} = - ## constructs a PEG from a terminal char - assert t != '\0' - result.kind = pkChar - result.ch = t - -proc charSet*(s: set[char]): TPeg {.rtl, extern: "npegs$1".} = - ## constructs a PEG from a character set `s` - assert '\0' notin s - result.kind = pkCharChoice - new(result.charChoice) - result.charChoice[] = s - -proc len(a: TPeg): int {.inline.} = return a.sons.len -proc add(d: var TPeg, s: TPeg) {.inline.} = add(d.sons, s) - -proc copyPeg(a: TPeg): TPeg = - result.kind = a.kind - case a.kind - of pkEmpty..pkWhitespace: discard - of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: - result.term = a.term - of pkChar, pkGreedyRepChar: - result.ch = a.ch - of pkCharChoice, pkGreedyRepSet: - new(result.charChoice) - result.charChoice[] = a.charChoice[] - of pkNonTerminal: result.nt = a.nt - of pkBackRef..pkBackRefIgnoreStyle: - result.index = a.index - else: - result.sons = a.sons - -proc addChoice(dest: var TPeg, elem: TPeg) = - var L = dest.len-1 - if L >= 0 and dest.sons[L].kind == pkCharChoice: - # caution! Do not introduce false aliasing here! - case elem.kind - of pkCharChoice: - dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[]) - of pkChar: - dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch}) - else: add(dest, elem) - else: add(dest, elem) - -template multipleOp(k: TPegKind, localOpt) = - result.kind = k - result.sons = @[] - for x in items(a): - if x.kind == k: - for y in items(x.sons): - localOpt(result, y) - else: - localOpt(result, x) - if result.len == 1: - result = result.sons[0] - -proc `/`*(a: varargs[TPeg]): TPeg {. - rtl, extern: "npegsOrderedChoice".} = - ## constructs an ordered choice with the PEGs in `a` - multipleOp(pkOrderedChoice, addChoice) - -proc addSequence(dest: var TPeg, elem: TPeg) = - var L = dest.len-1 - if L >= 0 and dest.sons[L].kind == pkTerminal: - # caution! Do not introduce false aliasing here! - case elem.kind - of pkTerminal: - dest.sons[L] = term(dest.sons[L].term & elem.term) - of pkChar: - dest.sons[L] = term(dest.sons[L].term & elem.ch) - else: add(dest, elem) - else: add(dest, elem) - -proc sequence*(a: varargs[TPeg]): TPeg {. - rtl, extern: "npegs$1".} = - ## constructs a sequence with all the PEGs from `a` - multipleOp(pkSequence, addSequence) - -proc `?`*(a: TPeg): TPeg {.rtl, extern: "npegsOptional".} = - ## constructs an optional for the PEG `a` - if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar, - pkGreedyRepSet}: - # a* ? --> a* - # a? ? --> a? - result = a - else: - result.kind = pkOption - result.sons = @[a] - -proc `*`*(a: TPeg): TPeg {.rtl, extern: "npegsGreedyRep".} = - ## constructs a "greedy repetition" for the PEG `a` - case a.kind - of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption: - assert false - # produces endless loop! - of pkChar: - result.kind = pkGreedyRepChar - result.ch = a.ch - of pkCharChoice: - result.kind = pkGreedyRepSet - result.charChoice = a.charChoice # copying a reference suffices! - of pkAny, pkAnyRune: - result.kind = pkGreedyAny - else: - result.kind = pkGreedyRep - result.sons = @[a] - -proc `!*`*(a: TPeg): TPeg {.rtl, extern: "npegsSearch".} = - ## constructs a "search" for the PEG `a` - result.kind = pkSearch - result.sons = @[a] - -proc `!*\`*(a: TPeg): TPeg {.rtl, - extern: "npgegsCapturedSearch".} = - ## constructs a "captured search" for the PEG `a` - result.kind = pkCapturedSearch - result.sons = @[a] - -when false: - proc contains(a: TPeg, k: TPegKind): bool = - if a.kind == k: return true - case a.kind - of pkEmpty, pkAny, pkAnyRune, pkGreedyAny, pkNewLine, pkTerminal, - pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, pkGreedyRepChar, - pkCharChoice, pkGreedyRepSet: discard - of pkNonTerminal: return true - else: - for i in 0..a.sons.len-1: - if contains(a.sons[i], k): return true - -proc `+`*(a: TPeg): TPeg {.rtl, extern: "npegsGreedyPosRep".} = - ## constructs a "greedy positive repetition" with the PEG `a` - return sequence(a, *a) - -proc `&`*(a: TPeg): TPeg {.rtl, extern: "npegsAndPredicate".} = - ## constructs an "and predicate" with the PEG `a` - result.kind = pkAndPredicate - result.sons = @[a] - -proc `!`*(a: TPeg): TPeg {.rtl, extern: "npegsNotPredicate".} = - ## constructs a "not predicate" with the PEG `a` - result.kind = pkNotPredicate - result.sons = @[a] - -proc any*: TPeg {.inline.} = - ## constructs the PEG `any character`:idx: (``.``) - result.kind = pkAny - -proc anyRune*: TPeg {.inline.} = - ## constructs the PEG `any rune`:idx: (``_``) - result.kind = pkAnyRune - -proc newLine*: TPeg {.inline.} = - ## constructs the PEG `newline`:idx: (``\n``) - result.kind = pkNewline - -proc UnicodeLetter*: TPeg {.inline.} = - ## constructs the PEG ``\letter`` which matches any Unicode letter. - result.kind = pkLetter - -proc UnicodeLower*: TPeg {.inline.} = - ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter. - result.kind = pkLower - -proc UnicodeUpper*: TPeg {.inline.} = - ## constructs the PEG ``\upper`` which matches any Unicode lowercase letter. - result.kind = pkUpper - -proc UnicodeTitle*: TPeg {.inline.} = - ## constructs the PEG ``\title`` which matches any Unicode title letter. - result.kind = pkTitle - -proc UnicodeWhitespace*: TPeg {.inline.} = - ## constructs the PEG ``\white`` which matches any Unicode - ## whitespace character. - result.kind = pkWhitespace - -proc startAnchor*: TPeg {.inline.} = - ## constructs the PEG ``^`` which matches the start of the input. - result.kind = pkStartAnchor - -proc endAnchor*: TPeg {.inline.} = - ## constructs the PEG ``$`` which matches the end of the input. - result = !any() - -proc capture*(a: TPeg): TPeg {.rtl, extern: "npegsCapture".} = - ## constructs a capture with the PEG `a` - result.kind = pkCapture - result.sons = @[a] - -proc backref*(index: range[1..MaxSubPatterns]): TPeg {. - rtl, extern: "npegs$1".} = - ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. - result.kind = pkBackRef - result.index = index-1 - -proc backrefIgnoreCase*(index: range[1..MaxSubPatterns]): TPeg {. - rtl, extern: "npegs$1".} = - ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. Ignores case for matching. - result.kind = pkBackRefIgnoreCase - result.index = index-1 - -proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg {. - rtl, extern: "npegs$1".}= - ## constructs a back reference of the given `index`. `index` starts counting - ## from 1. Ignores style for matching. - result.kind = pkBackRefIgnoreStyle - result.index = index-1 - -proc spaceCost(n: TPeg): int = - case n.kind - of pkEmpty: discard - of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, - pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, - pkAny..pkWhitespace, pkGreedyAny: - result = 1 - of pkNonTerminal: - # we cannot inline a rule with a non-terminal - result = InlineThreshold+1 - else: - for i in 0..n.len-1: - inc(result, spaceCost(n.sons[i])) - if result >= InlineThreshold: break - -proc nonterminal*(n: PNonTerminal): TPeg {. - rtl, extern: "npegs$1".} = - ## constructs a PEG that consists of the nonterminal symbol - assert n != nil - if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold: - when false: echo "inlining symbol: ", n.name - result = n.rule # inlining of rule enables better optimizations - else: - result.kind = pkNonTerminal - result.nt = n - -proc newNonTerminal*(name: string, line, column: int): PNonTerminal {. - rtl, extern: "npegs$1".} = - ## constructs a nonterminal symbol - new(result) - result.name = name - result.line = line - result.col = column - -template letters*: TPeg = - ## expands to ``charset({'A'..'Z', 'a'..'z'})`` - charset({'A'..'Z', 'a'..'z'}) - -template digits*: TPeg = - ## expands to ``charset({'0'..'9'})`` - charset({'0'..'9'}) - -template whitespace*: TPeg = - ## expands to ``charset({' ', '\9'..'\13'})`` - charset({' ', '\9'..'\13'}) - -template identChars*: TPeg = - ## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})`` - charset({'a'..'z', 'A'..'Z', '0'..'9', '_'}) - -template identStartChars*: TPeg = - ## expands to ``charset({'A'..'Z', 'a'..'z', '_'})`` - charset({'a'..'z', 'A'..'Z', '_'}) - -template ident*: TPeg = - ## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier - sequence(charset({'a'..'z', 'A'..'Z', '_'}), - *charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})) - -template natural*: TPeg = - ## same as ``\d+`` - +digits - -# ------------------------- debugging ----------------------------------------- - -proc esc(c: char, reserved = {'\0'..'\255'}): string = - case c - of '\b': result = "\\b" - of '\t': result = "\\t" - of '\c': result = "\\c" - of '\L': result = "\\l" - of '\v': result = "\\v" - of '\f': result = "\\f" - of '\e': result = "\\e" - of '\a': result = "\\a" - of '\\': result = "\\\\" - of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c - elif c < ' ' or c >= '\128': result = '\\' & $ord(c) - elif c in reserved: result = '\\' & c - else: result = $c - -proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'" - -proc singleQuoteEsc(str: string): string = - result = "'" - for c in items(str): add result, esc(c, {'\''}) - add result, '\'' - -proc charSetEscAux(cc: set[char]): string = - const reserved = {'^', '-', ']'} - result = "" - var c1 = 0 - while c1 <= 0xff: - if chr(c1) in cc: - var c2 = c1 - while c2 < 0xff and chr(succ(c2)) in cc: inc(c2) - if c1 == c2: - add result, esc(chr(c1), reserved) - elif c2 == succ(c1): - add result, esc(chr(c1), reserved) & esc(chr(c2), reserved) - else: - add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved) - c1 = c2 - inc(c1) - -proc charSetEsc(cc: set[char]): string = - if card(cc) >= 128+64: - result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']' - else: - result = '[' & charSetEscAux(cc) & ']' - -proc toStrAux(r: TPeg, res: var string) = - case r.kind - of pkEmpty: add(res, "()") - of pkAny: add(res, '.') - of pkAnyRune: add(res, '_') - of pkLetter: add(res, "\\letter") - of pkLower: add(res, "\\lower") - of pkUpper: add(res, "\\upper") - of pkTitle: add(res, "\\title") - of pkWhitespace: add(res, "\\white") - - of pkNewline: add(res, "\\n") - of pkTerminal: add(res, singleQuoteEsc(r.term)) - of pkTerminalIgnoreCase: - add(res, 'i') - add(res, singleQuoteEsc(r.term)) - of pkTerminalIgnoreStyle: - add(res, 'y') - add(res, singleQuoteEsc(r.term)) - of pkChar: add(res, singleQuoteEsc(r.ch)) - of pkCharChoice: add(res, charSetEsc(r.charChoice[])) - of pkNonTerminal: add(res, r.nt.name) - of pkSequence: - add(res, '(') - toStrAux(r.sons[0], res) - for i in 1 .. high(r.sons): - add(res, ' ') - toStrAux(r.sons[i], res) - add(res, ')') - of pkOrderedChoice: - add(res, '(') - toStrAux(r.sons[0], res) - for i in 1 .. high(r.sons): - add(res, " / ") - toStrAux(r.sons[i], res) - add(res, ')') - of pkGreedyRep: - toStrAux(r.sons[0], res) - add(res, '*') - of pkGreedyRepChar: - add(res, singleQuoteEsc(r.ch)) - add(res, '*') - of pkGreedyRepSet: - add(res, charSetEsc(r.charChoice[])) - add(res, '*') - of pkGreedyAny: - add(res, ".*") - of pkOption: - toStrAux(r.sons[0], res) - add(res, '?') - of pkAndPredicate: - add(res, '&') - toStrAux(r.sons[0], res) - of pkNotPredicate: - add(res, '!') - toStrAux(r.sons[0], res) - of pkSearch: - add(res, '@') - toStrAux(r.sons[0], res) - of pkCapturedSearch: - add(res, "{@}") - toStrAux(r.sons[0], res) - of pkCapture: - add(res, '{') - toStrAux(r.sons[0], res) - add(res, '}') - of pkBackRef: - add(res, '$') - add(res, $r.index) - of pkBackRefIgnoreCase: - add(res, "i$") - add(res, $r.index) - of pkBackRefIgnoreStyle: - add(res, "y$") - add(res, $r.index) - of pkRule: - toStrAux(r.sons[0], res) - add(res, " <- ") - toStrAux(r.sons[1], res) - of pkList: - for i in 0 .. high(r.sons): - toStrAux(r.sons[i], res) - add(res, "\n") - of pkStartAnchor: - add(res, '^') - -proc `$` *(r: TPeg): string {.rtl, extern: "npegsToString".} = - ## converts a PEG to its string representation - result = "" - toStrAux(r, result) - -# --------------------- core engine ------------------------------------------- - -type - TCaptures* {.final.} = object ## contains the captured substrings. - matches: array[0..MaxSubpatterns-1, tuple[first, last: int]] - ml: int - origStart: int - -proc bounds*(c: TCaptures, - i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = - ## returns the bounds ``[first..last]`` of the `i`'th capture. - result = c.matches[i] - -when not useUnicode: - type - Rune = char - template fastRuneAt(s, i, ch) = - ch = s[i] - inc(i) - template runeLenAt(s, i): untyped = 1 - - proc isAlpha(a: char): bool {.inline.} = return a in {'a'..'z','A'..'Z'} - proc isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'} - proc isLower(a: char): bool {.inline.} = return a in {'a'..'z'} - proc isTitle(a: char): bool {.inline.} = return false - proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'} - -proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. - rtl, extern: "npegs$1".} = - ## low-level matching proc that implements the PEG interpreter. Use this - ## for maximum efficiency (every other PEG operation ends up calling this - ## proc). - ## Returns -1 if it does not match, else the length of the match - case p.kind - of pkEmpty: result = 0 # match of length 0 - of pkAny: - if s[start] != '\0': result = 1 - else: result = -1 - of pkAnyRune: - if s[start] != '\0': - result = runeLenAt(s, start) - else: - result = -1 - of pkLetter: - if s[start] != '\0': - var a: Rune - result = start - fastRuneAt(s, result, a) - if isAlpha(a): dec(result, start) - else: result = -1 - else: - result = -1 - of pkLower: - if s[start] != '\0': - var a: Rune - result = start - fastRuneAt(s, result, a) - if isLower(a): dec(result, start) - else: result = -1 - else: - result = -1 - of pkUpper: - if s[start] != '\0': - var a: Rune - result = start - fastRuneAt(s, result, a) - if isUpper(a): dec(result, start) - else: result = -1 - else: - result = -1 - of pkTitle: - if s[start] != '\0': - var a: Rune - result = start - fastRuneAt(s, result, a) - if isTitle(a): dec(result, start) - else: result = -1 - else: - result = -1 - of pkWhitespace: - if s[start] != '\0': - var a: Rune - result = start - fastRuneAt(s, result, a) - if isWhitespace(a): dec(result, start) - else: result = -1 - else: - result = -1 - of pkGreedyAny: - result = len(s) - start - of pkNewLine: - if s[start] == '\L': result = 1 - elif s[start] == '\C': - if s[start+1] == '\L': result = 2 - else: result = 1 - else: result = -1 - of pkTerminal: - result = len(p.term) - for i in 0..result-1: - if p.term[i] != s[start+i]: - result = -1 - break - of pkTerminalIgnoreCase: - var - i = 0 - a, b: Rune - result = start - while i < len(p.term): - fastRuneAt(p.term, i, a) - fastRuneAt(s, result, b) - if toLower(a) != toLower(b): - result = -1 - break - dec(result, start) - of pkTerminalIgnoreStyle: - var - i = 0 - a, b: Rune - result = start - while i < len(p.term): - while true: - fastRuneAt(p.term, i, a) - if a != Rune('_'): break - while true: - fastRuneAt(s, result, b) - if b != Rune('_'): break - if toLower(a) != toLower(b): - result = -1 - break - dec(result, start) - of pkChar: - if p.ch == s[start]: result = 1 - else: result = -1 - of pkCharChoice: - if contains(p.charChoice[], s[start]): result = 1 - else: result = -1 - of pkNonTerminal: - var oldMl = c.ml - when false: echo "enter: ", p.nt.name - result = rawMatch(s, p.nt.rule, start, c) - when false: echo "leave: ", p.nt.name - if result < 0: c.ml = oldMl - of pkSequence: - var oldMl = c.ml - result = 0 - assert(not isNil(p.sons)) - for i in 0..high(p.sons): - var x = rawMatch(s, p.sons[i], start+result, c) - if x < 0: - c.ml = oldMl - result = -1 - break - else: inc(result, x) - of pkOrderedChoice: - var oldMl = c.ml - for i in 0..high(p.sons): - result = rawMatch(s, p.sons[i], start, c) - if result >= 0: break - c.ml = oldMl - of pkSearch: - var oldMl = c.ml - result = 0 - while start+result < s.len: - var x = rawMatch(s, p.sons[0], start+result, c) - if x >= 0: - inc(result, x) - return - inc(result) - result = -1 - c.ml = oldMl - of pkCapturedSearch: - var idx = c.ml # reserve a slot for the subpattern - inc(c.ml) - result = 0 - while start+result < s.len: - var x = rawMatch(s, p.sons[0], start+result, c) - if x >= 0: - if idx < MaxSubpatterns: - c.matches[idx] = (start, start+result-1) - #else: silently ignore the capture - inc(result, x) - return - inc(result) - result = -1 - c.ml = idx - of pkGreedyRep: - result = 0 - while true: - var x = rawMatch(s, p.sons[0], start+result, c) - # if x == 0, we have an endless loop; so the correct behaviour would be - # not to break. But endless loops can be easily introduced: - # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the - # expected thing in this case. - if x <= 0: break - inc(result, x) - of pkGreedyRepChar: - result = 0 - var ch = p.ch - while ch == s[start+result]: inc(result) - of pkGreedyRepSet: - result = 0 - while contains(p.charChoice[], s[start+result]): inc(result) - of pkOption: - result = max(0, rawMatch(s, p.sons[0], start, c)) - of pkAndPredicate: - var oldMl = c.ml - result = rawMatch(s, p.sons[0], start, c) - if result >= 0: result = 0 # do not consume anything - else: c.ml = oldMl - of pkNotPredicate: - var oldMl = c.ml - result = rawMatch(s, p.sons[0], start, c) - if result < 0: result = 0 - else: - c.ml = oldMl - result = -1 - of pkCapture: - var idx = c.ml # reserve a slot for the subpattern - inc(c.ml) - result = rawMatch(s, p.sons[0], start, c) - if result >= 0: - if idx < MaxSubpatterns: - c.matches[idx] = (start, start+result-1) - #else: silently ignore the capture - else: - c.ml = idx - of pkBackRef..pkBackRefIgnoreStyle: - if p.index >= c.ml: return -1 - var (a, b) = c.matches[p.index] - var n: TPeg - n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) - n.term = s.substr(a, b) - result = rawMatch(s, n, start, c) - of pkStartAnchor: - if c.origStart == start: result = 0 - else: result = -1 - of pkRule, pkList: assert false - -proc match*(s: string, pattern: TPeg, matches: var openarray[string], - start = 0): bool {.rtl, extern: "npegs$1Capture".} = - ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and - ## the captured substrings in the array ``matches``. If it does not - ## match, nothing is written into ``matches`` and ``false`` is - ## returned. - var c: TCaptures - c.origStart = start - result = rawMatch(s, pattern, start, c) == len(s)-start - if result: - for i in 0..c.ml-1: - matches[i] = substr(s, c.matches[i][0], c.matches[i][1]) - -proc match*(s: string, pattern: TPeg, - start = 0): bool {.rtl, extern: "npegs$1".} = - ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``. - var c: TCaptures - c.origStart = start - result = rawMatch(s, pattern, start, c) == len(s)-start - -proc matchLen*(s: string, pattern: TPeg, matches: var openarray[string], - start = 0): int {.rtl, extern: "npegs$1Capture".} = - ## the same as ``match``, but it returns the length of the match, - ## if there is no match, -1 is returned. Note that a match length - ## of zero can happen. It's possible that a suffix of `s` remains - ## that does not belong to the match. - var c: TCaptures - c.origStart = start - result = rawMatch(s, pattern, start, c) - if result >= 0: - for i in 0..c.ml-1: - matches[i] = substr(s, c.matches[i][0], c.matches[i][1]) - -proc matchLen*(s: string, pattern: TPeg, - start = 0): int {.rtl, extern: "npegs$1".} = - ## the same as ``match``, but it returns the length of the match, - ## if there is no match, -1 is returned. Note that a match length - ## of zero can happen. It's possible that a suffix of `s` remains - ## that does not belong to the match. - var c: TCaptures - c.origStart = start - result = rawMatch(s, pattern, start, c) - -proc find*(s: string, pattern: TPeg, matches: var openarray[string], - start = 0): int {.rtl, extern: "npegs$1Capture".} = - ## returns the starting position of ``pattern`` in ``s`` and the captured - ## substrings in the array ``matches``. If it does not match, nothing - ## is written into ``matches`` and -1 is returned. - for i in start .. s.len-1: - if matchLen(s, pattern, matches, i) >= 0: return i - return -1 - # could also use the pattern here: (!P .)* P - -proc findBounds*(s: string, pattern: TPeg, matches: var openarray[string], - start = 0): tuple[first, last: int] {. - rtl, extern: "npegs$1Capture".} = - ## returns the starting position and end position of ``pattern`` in ``s`` - ## and the captured - ## substrings in the array ``matches``. If it does not match, nothing - ## is written into ``matches`` and (-1,0) is returned. - for i in start .. s.len-1: - var L = matchLen(s, pattern, matches, i) - if L >= 0: return (i, i+L-1) - return (-1, 0) - -proc find*(s: string, pattern: TPeg, - start = 0): int {.rtl, extern: "npegs$1".} = - ## returns the starting position of ``pattern`` in ``s``. If it does not - ## match, -1 is returned. - for i in start .. s.len-1: - if matchLen(s, pattern, i) >= 0: return i - return -1 - -iterator findAll*(s: string, pattern: TPeg, start = 0): string = - ## yields all matching captures of pattern in `s`. - var matches: array[0..MaxSubpatterns-1, string] - var i = start - while i < s.len: - var L = matchLen(s, pattern, matches, i) - if L < 0: break - for k in 0..MaxSubPatterns-1: - if isNil(matches[k]): break - yield matches[k] - inc(i, L) - -proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {. - rtl, extern: "npegs$1".} = - ## returns all matching captures of pattern in `s`. - ## If it does not match, @[] is returned. - accumulateResult(findAll(s, pattern, start)) - -template `=~`*(s: string, pattern: TPeg): untyped = - ## This calls ``match`` with an implicit declared ``matches`` array that - ## can be used in the scope of the ``=~`` call: - ## - ## .. code-block:: nim - ## - ## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}": - ## # matches a key=value pair: - ## echo("Key: ", matches[0]) - ## echo("Value: ", matches[1]) - ## elif line =~ peg"\s*{'#'.*}": - ## # matches a comment - ## # note that the implicit ``matches`` array is different from the - ## # ``matches`` array of the first branch - ## echo("comment: ", matches[0]) - ## else: - ## echo("syntax error") - ## - when not declaredInScope(matches): - var matches {.inject.}: array[0..MaxSubpatterns-1, string] - match(s, pattern, matches) - -# ------------------------- more string handling ------------------------------ - -proc contains*(s: string, pattern: TPeg, start = 0): bool {. - rtl, extern: "npegs$1".} = - ## same as ``find(s, pattern, start) >= 0`` - return find(s, pattern, start) >= 0 - -proc contains*(s: string, pattern: TPeg, matches: var openArray[string], - start = 0): bool {.rtl, extern: "npegs$1Capture".} = - ## same as ``find(s, pattern, matches, start) >= 0`` - return find(s, pattern, matches, start) >= 0 - -proc startsWith*(s: string, prefix: TPeg, start = 0): bool {. - rtl, extern: "npegs$1".} = - ## returns true if `s` starts with the pattern `prefix` - result = matchLen(s, prefix, start) >= 0 - -proc endsWith*(s: string, suffix: TPeg, start = 0): bool {. - rtl, extern: "npegs$1".} = - ## returns true if `s` ends with the pattern `prefix` - for i in start .. s.len-1: - if matchLen(s, suffix, i) == s.len - i: return true - -proc replacef*(s: string, sub: TPeg, by: string): string {. - rtl, extern: "npegs$1".} = - ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` - ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: - ## - ## .. code-block:: nim - ## "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") - ## - ## Results in: - ## - ## .. code-block:: nim - ## - ## "var1<-keykey; val2<-key2key2" - result = "" - var i = 0 - var caps: array[0..MaxSubpatterns-1, string] - while i < s.len: - var x = matchLen(s, sub, caps, i) - if x <= 0: - add(result, s[i]) - inc(i) - else: - addf(result, by, caps) - inc(i, x) - add(result, substr(s, i)) - -proc replace*(s: string, sub: TPeg, by = ""): string {. - rtl, extern: "npegs$1".} = - ## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed - ## in `by`. - result = "" - var i = 0 - var caps: array[0..MaxSubpatterns-1, string] - while i < s.len: - var x = matchLen(s, sub, caps, i) - if x <= 0: - add(result, s[i]) - inc(i) - else: - addf(result, by, caps) - inc(i, x) - add(result, substr(s, i)) - -proc parallelReplace*(s: string, subs: varargs[ - tuple[pattern: TPeg, repl: string]]): string {. - rtl, extern: "npegs$1".} = - ## Returns a modified copy of `s` with the substitutions in `subs` - ## applied in parallel. - result = "" - var i = 0 - var caps: array[0..MaxSubpatterns-1, string] - while i < s.len: - block searchSubs: - for j in 0..high(subs): - var x = matchLen(s, subs[j][0], caps, i) - if x > 0: - addf(result, subs[j][1], caps) - inc(i, x) - break searchSubs - add(result, s[i]) - inc(i) - # copy the rest: - add(result, substr(s, i)) - -proc transformFile*(infile, outfile: string, - subs: varargs[tuple[pattern: TPeg, repl: string]]) {. - rtl, extern: "npegs$1".} = - ## reads in the file `infile`, performs a parallel replacement (calls - ## `parallelReplace`) and writes back to `outfile`. Calls ``quit`` if an - ## error occurs. This is supposed to be used for quick scripting. - var x = readFile(infile) - if not isNil(x): - var f: File - if open(f, outfile, fmWrite): - write(f, x.parallelReplace(subs)) - close(f) - else: - quit("cannot open for writing: " & outfile) - else: - quit("cannot open for reading: " & infile) - -iterator split*(s: string, sep: TPeg): string = - ## Splits the string `s` into substrings. - ## - ## Substrings are separated by the PEG `sep`. - ## Examples: - ## - ## .. code-block:: nim - ## for word in split("00232this02939is39an22example111", peg"\d+"): - ## writeLine(stdout, word) - ## - ## Results in: - ## - ## .. code-block:: nim - ## "this" - ## "is" - ## "an" - ## "example" - ## - var - first = 0 - last = 0 - while last < len(s): - var x = matchLen(s, sep, last) - if x > 0: inc(last, x) - first = last - while last < len(s): - inc(last) - x = matchLen(s, sep, last) - if x > 0: break - if first < last: - yield substr(s, first, last-1) - -proc split*(s: string, sep: TPeg): seq[string] {. - rtl, extern: "npegs$1".} = - ## Splits the string `s` into substrings. - accumulateResult(split(s, sep)) - -# ------------------- scanner ------------------------------------------------- - -type - TModifier = enum - modNone, - modVerbatim, - modIgnoreCase, - modIgnoreStyle - TTokKind = enum ## enumeration of all tokens - tkInvalid, ## invalid token - tkEof, ## end of file reached - tkAny, ## . - tkAnyRune, ## _ - tkIdentifier, ## abc - tkStringLit, ## "abc" or 'abc' - tkCharSet, ## [^A-Z] - tkParLe, ## '(' - tkParRi, ## ')' - tkCurlyLe, ## '{' - tkCurlyRi, ## '}' - tkCurlyAt, ## '{@}' - tkArrow, ## '<-' - tkBar, ## '/' - tkStar, ## '*' - tkPlus, ## '+' - tkAmp, ## '&' - tkNot, ## '!' - tkOption, ## '?' - tkAt, ## '@' - tkBuiltin, ## \identifier - tkEscaped, ## \\ - tkBackref, ## '$' - tkDollar, ## '$' - tkHat ## '^' - - TToken {.final.} = object ## a token - kind: TTokKind ## the type of the token - modifier: TModifier - literal: string ## the parsed (string) literal - charset: set[char] ## if kind == tkCharSet - index: int ## if kind == tkBackref - - TPegLexer {.inheritable.} = object ## the lexer object. - bufpos: int ## the current position within the buffer - buf: cstring ## the buffer itself - lineNumber: int ## the current line number - lineStart: int ## index of last line start in buffer - colOffset: int ## column to add - filename: string - -const - tokKindToStr: array[TTokKind, string] = [ - "invalid", "[EOF]", ".", "_", "identifier", "string literal", - "character set", "(", ")", "{", "}", "{@}", - "<-", "/", "*", "+", "&", "!", "?", - "@", "built-in", "escaped", "$", "$", "^" - ] - -proc HandleCR(L: var TPegLexer, pos: int): int = - assert(L.buf[pos] == '\c') - inc(L.linenumber) - result = pos+1 - if L.buf[result] == '\L': inc(result) - L.lineStart = result - -proc HandleLF(L: var TPegLexer, pos: int): int = - assert(L.buf[pos] == '\L') - inc(L.linenumber) - result = pos+1 - L.lineStart = result - -proc init(L: var TPegLexer, input, filename: string, line = 1, col = 0) = - L.buf = input - L.bufpos = 0 - L.lineNumber = line - L.colOffset = col - L.lineStart = 0 - L.filename = filename - -proc getColumn(L: TPegLexer): int {.inline.} = - result = abs(L.bufpos - L.lineStart) + L.colOffset - -proc getLine(L: TPegLexer): int {.inline.} = - result = L.linenumber - -proc errorStr(L: TPegLexer, msg: string, line = -1, col = -1): string = - var line = if line < 0: getLine(L) else: line - var col = if col < 0: getColumn(L) else: col - result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg] - -proc handleHexChar(c: var TPegLexer, xi: var int) = - case c.buf[c.bufpos] - of '0'..'9': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) - inc(c.bufpos) - of 'a'..'f': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10) - inc(c.bufpos) - of 'A'..'F': - xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10) - inc(c.bufpos) - else: discard - -proc getEscapedChar(c: var TPegLexer, tok: var TToken) = - inc(c.bufpos) - case c.buf[c.bufpos] - of 'r', 'R', 'c', 'C': - add(tok.literal, '\c') - inc(c.bufpos) - of 'l', 'L': - add(tok.literal, '\L') - inc(c.bufpos) - of 'f', 'F': - add(tok.literal, '\f') - inc(c.bufpos) - of 'e', 'E': - add(tok.literal, '\e') - inc(c.bufpos) - of 'a', 'A': - add(tok.literal, '\a') - inc(c.bufpos) - of 'b', 'B': - add(tok.literal, '\b') - inc(c.bufpos) - of 'v', 'V': - add(tok.literal, '\v') - inc(c.bufpos) - of 't', 'T': - add(tok.literal, '\t') - inc(c.bufpos) - of 'x', 'X': - inc(c.bufpos) - var xi = 0 - handleHexChar(c, xi) - handleHexChar(c, xi) - if xi == 0: tok.kind = tkInvalid - else: add(tok.literal, chr(xi)) - of '0'..'9': - var val = ord(c.buf[c.bufpos]) - ord('0') - inc(c.bufpos) - var i = 1 - while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): - val = val * 10 + ord(c.buf[c.bufpos]) - ord('0') - inc(c.bufpos) - inc(i) - if val > 0 and val <= 255: add(tok.literal, chr(val)) - else: tok.kind = tkInvalid - of '\0'..'\31': - tok.kind = tkInvalid - elif c.buf[c.bufpos] in strutils.Letters: - tok.kind = tkInvalid - else: - add(tok.literal, c.buf[c.bufpos]) - inc(c.bufpos) - -proc skip(c: var TPegLexer) = - var pos = c.bufpos - var buf = c.buf - while true: - case buf[pos] - of ' ', '\t': - inc(pos) - of '#': - while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos) - of '\c': - pos = HandleCR(c, pos) - buf = c.buf - of '\L': - pos = HandleLF(c, pos) - buf = c.buf - else: - break # EndOfFile also leaves the loop - c.bufpos = pos - -proc getString(c: var TPegLexer, tok: var TToken) = - tok.kind = tkStringLit - var pos = c.bufPos + 1 - var buf = c.buf - var quote = buf[pos-1] - while true: - case buf[pos] - of '\\': - c.bufpos = pos - getEscapedChar(c, tok) - pos = c.bufpos - of '\c', '\L', '\0': - tok.kind = tkInvalid - break - elif buf[pos] == quote: - inc(pos) - break - else: - add(tok.literal, buf[pos]) - inc(pos) - c.bufpos = pos - -proc getDollar(c: var TPegLexer, tok: var TToken) = - var pos = c.bufPos + 1 - var buf = c.buf - if buf[pos] in {'0'..'9'}: - tok.kind = tkBackref - tok.index = 0 - while buf[pos] in {'0'..'9'}: - tok.index = tok.index * 10 + ord(buf[pos]) - ord('0') - inc(pos) - else: - tok.kind = tkDollar - c.bufpos = pos - -proc getCharSet(c: var TPegLexer, tok: var TToken) = - tok.kind = tkCharSet - tok.charset = {} - var pos = c.bufPos + 1 - var buf = c.buf - var caret = false - if buf[pos] == '^': - inc(pos) - caret = true - while true: - var ch: char - case buf[pos] - of ']': - inc(pos) - break - of '\\': - c.bufpos = pos - getEscapedChar(c, tok) - pos = c.bufpos - ch = tok.literal[tok.literal.len-1] - of '\C', '\L', '\0': - tok.kind = tkInvalid - break - else: - ch = buf[pos] - inc(pos) - incl(tok.charset, ch) - if buf[pos] == '-': - if buf[pos+1] == ']': - incl(tok.charset, '-') - inc(pos) - else: - inc(pos) - var ch2: char - case buf[pos] - of '\\': - c.bufpos = pos - getEscapedChar(c, tok) - pos = c.bufpos - ch2 = tok.literal[tok.literal.len-1] - of '\C', '\L', '\0': - tok.kind = tkInvalid - break - else: - ch2 = buf[pos] - inc(pos) - for i in ord(ch)+1 .. ord(ch2): - incl(tok.charset, chr(i)) - c.bufpos = pos - if caret: tok.charset = {'\1'..'\xFF'} - tok.charset - -proc getSymbol(c: var TPegLexer, tok: var TToken) = - var pos = c.bufpos - var buf = c.buf - while true: - add(tok.literal, buf[pos]) - inc(pos) - if buf[pos] notin strutils.IdentChars: break - c.bufpos = pos - tok.kind = tkIdentifier - -proc getBuiltin(c: var TPegLexer, tok: var TToken) = - if c.buf[c.bufpos+1] in strutils.Letters: - inc(c.bufpos) - getSymbol(c, tok) - tok.kind = tkBuiltin - else: - tok.kind = tkEscaped - getEscapedChar(c, tok) # may set tok.kind to tkInvalid - -proc getTok(c: var TPegLexer, tok: var TToken) = - tok.kind = tkInvalid - tok.modifier = modNone - setlen(tok.literal, 0) - skip(c) - case c.buf[c.bufpos] - of '{': - inc(c.bufpos) - if c.buf[c.bufpos] == '@' and c.buf[c.bufpos+1] == '}': - tok.kind = tkCurlyAt - inc(c.bufpos, 2) - add(tok.literal, "{@}") - else: - tok.kind = tkCurlyLe - add(tok.literal, '{') - of '}': - tok.kind = tkCurlyRi - inc(c.bufpos) - add(tok.literal, '}') - of '[': - getCharset(c, tok) - of '(': - tok.kind = tkParLe - inc(c.bufpos) - add(tok.literal, '(') - of ')': - tok.kind = tkParRi - inc(c.bufpos) - add(tok.literal, ')') - of '.': - tok.kind = tkAny - inc(c.bufpos) - add(tok.literal, '.') - of '_': - tok.kind = tkAnyRune - inc(c.bufpos) - add(tok.literal, '_') - of '\\': - getBuiltin(c, tok) - of '\'', '"': getString(c, tok) - of '$': getDollar(c, tok) - of '\0': - tok.kind = tkEof - tok.literal = "[EOF]" - of 'a'..'z', 'A'..'Z', '\128'..'\255': - getSymbol(c, tok) - if c.buf[c.bufpos] in {'\'', '"'} or - c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}: - case tok.literal - of "i": tok.modifier = modIgnoreCase - of "y": tok.modifier = modIgnoreStyle - of "v": tok.modifier = modVerbatim - else: discard - setLen(tok.literal, 0) - if c.buf[c.bufpos] == '$': - getDollar(c, tok) - else: - getString(c, tok) - if tok.modifier == modNone: tok.kind = tkInvalid - of '+': - tok.kind = tkPlus - inc(c.bufpos) - add(tok.literal, '+') - of '*': - tok.kind = tkStar - inc(c.bufpos) - add(tok.literal, '+') - of '<': - if c.buf[c.bufpos+1] == '-': - inc(c.bufpos, 2) - tok.kind = tkArrow - add(tok.literal, "<-") - else: - add(tok.literal, '<') - of '/': - tok.kind = tkBar - inc(c.bufpos) - add(tok.literal, '/') - of '?': - tok.kind = tkOption - inc(c.bufpos) - add(tok.literal, '?') - of '!': - tok.kind = tkNot - inc(c.bufpos) - add(tok.literal, '!') - of '&': - tok.kind = tkAmp - inc(c.bufpos) - add(tok.literal, '!') - of '@': - tok.kind = tkAt - inc(c.bufpos) - add(tok.literal, '@') - if c.buf[c.bufpos] == '@': - tok.kind = tkCurlyAt - inc(c.bufpos) - add(tok.literal, '@') - of '^': - tok.kind = tkHat - inc(c.bufpos) - add(tok.literal, '^') - else: - add(tok.literal, c.buf[c.bufpos]) - inc(c.bufpos) - -proc arrowIsNextTok(c: TPegLexer): bool = - # the only look ahead we need - var pos = c.bufpos - while c.buf[pos] in {'\t', ' '}: inc(pos) - result = c.buf[pos] == '<' and c.buf[pos+1] == '-' - -# ----------------------------- parser ---------------------------------------- - -type - EInvalidPeg* = object of ValueError ## raised if an invalid - ## PEG has been detected - TPegParser = object of TPegLexer ## the PEG parser object - tok: TToken - nonterms: seq[PNonTerminal] - modifier: TModifier - captures: int - identIsVerbatim: bool - skip: TPeg - -proc pegError(p: TPegParser, msg: string, line = -1, col = -1) = - var e: ref EInvalidPeg - new(e) - e.msg = errorStr(p, msg, line, col) - raise e - -proc getTok(p: var TPegParser) = - getTok(p, p.tok) - if p.tok.kind == tkInvalid: pegError(p, "invalid token") - -proc eat(p: var TPegParser, kind: TTokKind) = - if p.tok.kind == kind: getTok(p) - else: pegError(p, tokKindToStr[kind] & " expected") - -proc parseExpr(p: var TPegParser): TPeg - -proc getNonTerminal(p: var TPegParser, name: string): PNonTerminal = - for i in 0..high(p.nonterms): - result = p.nonterms[i] - if cmpIgnoreStyle(result.name, name) == 0: return - # forward reference: - result = newNonTerminal(name, getLine(p), getColumn(p)) - add(p.nonterms, result) - -proc modifiedTerm(s: string, m: TModifier): TPeg = - case m - of modNone, modVerbatim: result = term(s) - of modIgnoreCase: result = termIgnoreCase(s) - of modIgnoreStyle: result = termIgnoreStyle(s) - -proc modifiedBackref(s: int, m: TModifier): TPeg = - case m - of modNone, modVerbatim: result = backRef(s) - of modIgnoreCase: result = backRefIgnoreCase(s) - of modIgnoreStyle: result = backRefIgnoreStyle(s) - -proc builtin(p: var TPegParser): TPeg = - # do not use "y", "skip" or "i" as these would be ambiguous - case p.tok.literal - of "n": result = newLine() - of "d": result = charset({'0'..'9'}) - of "D": result = charset({'\1'..'\xff'} - {'0'..'9'}) - of "s": result = charset({' ', '\9'..'\13'}) - of "S": result = charset({'\1'..'\xff'} - {' ', '\9'..'\13'}) - of "w": result = charset({'a'..'z', 'A'..'Z', '_', '0'..'9'}) - of "W": result = charset({'\1'..'\xff'} - {'a'..'z','A'..'Z','_','0'..'9'}) - of "a": result = charset({'a'..'z', 'A'..'Z'}) - of "A": result = charset({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'}) - of "ident": result = tpegs.ident - of "letter": result = UnicodeLetter() - of "upper": result = UnicodeUpper() - of "lower": result = UnicodeLower() - of "title": result = UnicodeTitle() - of "white": result = UnicodeWhitespace() - else: pegError(p, "unknown built-in: " & p.tok.literal) - -proc token(terminal: TPeg, p: TPegParser): TPeg = - if p.skip.kind == pkEmpty: result = terminal - else: result = sequence(p.skip, terminal) - -proc primary(p: var TPegParser): TPeg = - case p.tok.kind - of tkAmp: - getTok(p) - return &primary(p) - of tkNot: - getTok(p) - return !primary(p) - of tkAt: - getTok(p) - return !*primary(p) - of tkCurlyAt: - getTok(p) - return !*\primary(p).token(p) - else: discard - case p.tok.kind - of tkIdentifier: - if p.identIsVerbatim: - var m = p.tok.modifier - if m == modNone: m = p.modifier - result = modifiedTerm(p.tok.literal, m).token(p) - getTok(p) - elif not arrowIsNextTok(p): - var nt = getNonTerminal(p, p.tok.literal) - incl(nt.flags, ntUsed) - result = nonTerminal(nt).token(p) - getTok(p) - else: - pegError(p, "expression expected, but found: " & p.tok.literal) - of tkStringLit: - var m = p.tok.modifier - if m == modNone: m = p.modifier - result = modifiedTerm(p.tok.literal, m).token(p) - getTok(p) - of tkCharSet: - if '\0' in p.tok.charset: - pegError(p, "binary zero ('\\0') not allowed in character class") - result = charset(p.tok.charset).token(p) - getTok(p) - of tkParLe: - getTok(p) - result = parseExpr(p) - eat(p, tkParRi) - of tkCurlyLe: - getTok(p) - result = capture(parseExpr(p)).token(p) - eat(p, tkCurlyRi) - inc(p.captures) - of tkAny: - result = any().token(p) - getTok(p) - of tkAnyRune: - result = anyRune().token(p) - getTok(p) - of tkBuiltin: - result = builtin(p).token(p) - getTok(p) - of tkEscaped: - result = term(p.tok.literal[0]).token(p) - getTok(p) - of tkDollar: - result = endAnchor() - getTok(p) - of tkHat: - result = startAnchor() - getTok(p) - of tkBackref: - var m = p.tok.modifier - if m == modNone: m = p.modifier - result = modifiedBackRef(p.tok.index, m).token(p) - if p.tok.index < 0 or p.tok.index > p.captures: - pegError(p, "invalid back reference index: " & $p.tok.index) - getTok(p) - else: - pegError(p, "expression expected, but found: " & p.tok.literal) - getTok(p) # we must consume a token here to prevent endless loops! - while true: - case p.tok.kind - of tkOption: - result = ?result - getTok(p) - of tkStar: - result = *result - getTok(p) - of tkPlus: - result = +result - getTok(p) - else: break - -proc seqExpr(p: var TPegParser): TPeg = - result = primary(p) - while true: - case p.tok.kind - of tkAmp, tkNot, tkAt, tkStringLit, tkCharset, tkParLe, tkCurlyLe, - tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, - tkHat, tkCurlyAt: - result = sequence(result, primary(p)) - of tkIdentifier: - if not arrowIsNextTok(p): - result = sequence(result, primary(p)) - else: break - else: break - -proc parseExpr(p: var TPegParser): TPeg = - result = seqExpr(p) - while p.tok.kind == tkBar: - getTok(p) - result = result / seqExpr(p) - -proc parseRule(p: var TPegParser): PNonTerminal = - if p.tok.kind == tkIdentifier and arrowIsNextTok(p): - result = getNonTerminal(p, p.tok.literal) - if ntDeclared in result.flags: - pegError(p, "attempt to redefine: " & result.name) - result.line = getLine(p) - result.col = getColumn(p) - getTok(p) - eat(p, tkArrow) - result.rule = parseExpr(p) - incl(result.flags, ntDeclared) # NOW inlining may be attempted - else: - pegError(p, "rule expected, but found: " & p.tok.literal) - -proc rawParse(p: var TPegParser): TPeg = - ## parses a rule or a PEG expression - while p.tok.kind == tkBuiltin: - case p.tok.literal - of "i": - p.modifier = modIgnoreCase - getTok(p) - of "y": - p.modifier = modIgnoreStyle - getTok(p) - of "skip": - getTok(p) - p.skip = ?primary(p) - else: break - if p.tok.kind == tkIdentifier and arrowIsNextTok(p): - result = parseRule(p).rule - while p.tok.kind != tkEof: - discard parseRule(p) - else: - p.identIsVerbatim = true - result = parseExpr(p) - if p.tok.kind != tkEof: - pegError(p, "EOF expected, but found: " & p.tok.literal) - for i in 0..high(p.nonterms): - var nt = p.nonterms[i] - if ntDeclared notin nt.flags: - pegError(p, "undeclared identifier: " & nt.name, nt.line, nt.col) - elif ntUsed notin nt.flags and i > 0: - pegError(p, "unused rule: " & nt.name, nt.line, nt.col) - -proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg = - ## constructs a TPeg object from `pattern`. `filename`, `line`, `col` are - ## used for error messages, but they only provide start offsets. `parsePeg` - ## keeps track of line and column numbers within `pattern`. - var p: TPegParser - init(TPegLexer(p), pattern, filename, line, col) - p.tok.kind = tkInvalid - p.tok.modifier = modNone - p.tok.literal = "" - p.tok.charset = {} - p.nonterms = @[] - p.identIsVerbatim = false - getTok(p) - result = rawParse(p) - -proc peg*(pattern: string): TPeg = - ## constructs a TPeg object from the `pattern`. The short name has been - ## chosen to encourage its use as a raw string modifier:: - ## - ## peg"{\ident} \s* '=' \s* {.*}" - result = parsePeg(pattern, "pattern") - -proc escapePeg*(s: string): string = - ## escapes `s` so that it is matched verbatim when used as a peg. - result = "" - var inQuote = false - for c in items(s): - case c - of '\0'..'\31', '\'', '"', '\\': - if inQuote: - result.add('\'') - inQuote = false - result.add("\\x") - result.add(toHex(ord(c), 2)) - else: - if not inQuote: - result.add('\'') - inQuote = true - result.add(c) - if inQuote: result.add('\'') - -when isMainModule: - doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" - #doAssert match("(a b c)", peg"'(' @ ')'") - doAssert match("W_HI_Le", peg"\y 'while'") - doAssert(not match("W_HI_L", peg"\y 'while'")) - doAssert(not match("W_HI_Le", peg"\y v'while'")) - doAssert match("W_HI_Le", peg"y'while'") - - doAssert($ +digits == $peg"\d+") - doAssert "0158787".match(peg"\d+") - doAssert "ABC 0232".match(peg"\w+\s+\d+") - doAssert "ABC".match(peg"\d+ / \w+") - - for word in split("00232this02939is39an22example111", peg"\d+"): - writeLine(stdout, word) - - doAssert matchLen("key", ident) == 3 - - var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident) - doAssert matchLen("key1= cal9", pattern) == 11 - - var ws = newNonTerminal("ws", 1, 1) - ws.rule = *whitespace - - var expr = newNonTerminal("expr", 1, 1) - expr.rule = sequence(capture(ident), *sequence( - nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) - - var c: TCaptures - var s = "a+b + c +d+e+f" - doAssert rawMatch(s, expr.rule, 0, c) == len(s) - var a = "" - for i in 0..c.ml-1: - a.add(substr(s, c.matches[i][0], c.matches[i][1])) - doAssert a == "abcdef" - #echo expr.rule - - #const filename = "lib/devel/peg/grammar.txt" - #var grammar = parsePeg(newFileStream(filename, fmRead), filename) - #echo "a <- [abc]*?".match(grammar) - doAssert find("_____abc_______", term("abc"), 2) == 5 - doAssert match("_______ana", peg"A <- 'ana' / . A") - doAssert match("abcs%%%", peg"A <- ..A / .A / '%'") - - if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": - doAssert matches[0] == "abc" - else: - doAssert false - - var g2 = peg"""S <- A B / C D - A <- 'a'+ - B <- 'b'+ - C <- 'c'+ - D <- 'd'+ - """ - doAssert($g2 == "((A B) / (C D))") - doAssert match("cccccdddddd", g2) - doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == - "var1<-keykey; var2<-key2key2") - doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") - - if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": - doAssert matches[0] == "a" - else: - doAssert false - - block: - var matches: array[0..2, string] - if match("abcdefg", peg"c {d} ef {g}", matches, 2): - doAssert matches[0] == "d" - doAssert matches[1] == "g" - else: - doAssert false - - for x in findAll("abcdef", peg"{.}", 3): - echo x - - if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": - doAssert matches[0] == "f" - doAssert matches[1] == "a, b" - else: - doAssert false - - doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+") - # ß is not a lower cased letter?! - doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+") - doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") - doAssert(not match("456678", peg"(\letter)+")) - - doAssert("var1 = key; var2 = key2".replacef( - peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") == - "var1<-keykey;var2<-key2key2") - - doAssert match("prefix/start", peg"^start$", 7) - - # tricky test to check for false aliasing: - block: - var a = term"key" - echo($sequence(sequence(a, term"value"), *a)) - From 83d4a025e26e55034a5b01a0bade25f8cc517c1a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Apr 2018 01:30:23 +0200 Subject: [PATCH 100/214] make logging module compile again --- lib/pure/logging.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 751fc0e8dd..43b5ab3aba 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -126,7 +126,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str var v = "" let app = when defined(js): "" else: getAppFilename() while frmt[i] in IdentChars: - v.add(toLower(frmt[i])) + v.add(toLowerAscii(frmt[i])) inc(i) case v of "date": result.add(getDateStr()) From f0eb3505fafe34bb11e0f335c322a50ae1f10e36 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Apr 2018 02:00:17 +0200 Subject: [PATCH 101/214] make asyncnet work again --- lib/pure/asyncnet.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index a75f9daacc..7c354151b3 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -201,7 +201,7 @@ when defineSsl: flags: set[SocketFlag]) {.async.} = let len = bioCtrlPending(socket.bioOut) if len > 0: - var data = newStringOfCap(len) + var data = newString(len) let read = bioRead(socket.bioOut, addr data[0], len) assert read != 0 if read < 0: From 0fad659bf72a48d076978655dd23fe369c2d232e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Apr 2018 02:52:58 +0200 Subject: [PATCH 102/214] make more tests green --- changelog.md | 3 +++ lib/pure/base64.nim | 8 ++++---- lib/pure/cookies.nim | 10 +++++----- lib/pure/httpcore.nim | 4 ++-- lib/pure/httpserver.nim | 8 ++++---- lib/pure/matchers.nim | 16 ++++++++-------- lib/pure/strutils.nim | 2 +- lib/pure/xmldom.nim | 14 +++++++------- tests/async/tlambda.nim | 4 ++-- 9 files changed, 36 insertions(+), 33 deletions(-) diff --git a/changelog.md b/changelog.md index 17c169d227..251aca4ab7 100644 --- a/changelog.md +++ b/changelog.md @@ -83,6 +83,9 @@ - ``nil`` for strings/seqs is finally gone. Instead the default value for these is ``"" / @[]``. +- Accessing the binary zero terminator in Nim's native strings + is now invalid. Internally a Nim string still has the trailing zero for + zero-copy interoperability with ``cstring``. ### Tool changes diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 4b0d082928..bfb8a16663 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -52,7 +52,7 @@ template encodeInternal(s: typed, lineLen: int, newLine: string): untyped = if numLines > 0: inc(total, (numLines - 1) * newLine.len) result = newString(total) - var + var i = 0 r = 0 currLine = 0 @@ -76,7 +76,7 @@ template encodeInternal(s: typed, lineLen: int, newLine: string): untyped = currLine = 0 if i < s.len-1: - let + let a = ord(s[i]) b = ord(s[i+1]) result[r] = cb64[a shr 2] @@ -130,11 +130,11 @@ proc decode*(s: string): string = # total is an upper bound, as we will skip arbitrary whitespace: result = newString(total) - var + var i = 0 r = 0 while true: - while s[i] in Whitespace: inc(i) + while i < s.len and s[i] in Whitespace: inc(i) if i < s.len-3: let a = s[i].decodeByte diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index aca0ac2b43..eaff86ae6a 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -25,16 +25,16 @@ proc parseCookies*(s: string): StringTableRef = result = newStringTable(modeCaseInsensitive) var i = 0 while true: - while s[i] == ' ' or s[i] == '\t': inc(i) + while i < s.len and (s[i] == ' ' or s[i] == '\t'): inc(i) var keystart = i - while s[i] != '=' and s[i] != '\0': inc(i) + while i < s.len and s[i] != '=': inc(i) var keyend = i-1 - if s[i] == '\0': break + if i >= s.len: break inc(i) # skip '=' var valstart = i - while s[i] != ';' and s[i] != '\0': inc(i) + while i < s.len and s[i] != ';': inc(i) result[substr(s, keystart, keyend)] = substr(s, valstart, i-1) - if s[i] == '\0': break + if i >= s.len: break inc(i) # skip ';' proc setCookie*(key, value: string, domain = "", path = "", diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index f150fa1c1a..5df26fdd58 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -190,11 +190,11 @@ proc len*(headers: HttpHeaders): int = return headers.table.len proc parseList(line: string, list: var seq[string], start: int): int = var i = 0 var current = "" - while line[start + i] notin {'\c', '\l', '\0'}: + while start+i < line.len and line[start + i] notin {'\c', '\l'}: i += line.skipWhitespace(start + i) i += line.parseUntil(current, {'\c', '\l', ','}, start + i) list.add(current) - if line[start + i] == ',': + if start+i < line.len and line[start + i] == ',': i.inc # Skip , current.setLen(0) diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim index 632eb198a1..9f54ed9e83 100644 --- a/lib/pure/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -126,7 +126,7 @@ when false: var dataAvail = false while dataAvail: dataAvail = recvLine(client, buf) # TODO: This is incorrect. - var L = toLower(buf.string) + var L = toLowerAscii(buf.string) if L.startsWith("content-length:"): var i = len("content-length:") while L[i] in Whitespace: inc(i) @@ -199,7 +199,7 @@ when false: notFound(client) else: when defined(Windows): - var ext = splitFile(path).ext.toLower + var ext = splitFile(path).ext.toLowerAscii if ext == ".exe" or ext == ".cgi": # XXX: extract interpreter information here? cgi = true @@ -303,7 +303,7 @@ proc next*(s: var Server) = if s.reqMethod == "POST": # Check for Expect header if s.headers.hasKey("Expect"): - if s.headers["Expect"].toLower == "100-continue": + if s.headers["Expect"].toLowerAscii == "100-continue": s.client.sendStatus("100 Continue") else: s.client.sendStatus("417 Expectation Failed") @@ -427,7 +427,7 @@ proc nextAsync(s: PAsyncHTTPServer) = if s.reqMethod == "POST": # Check for Expect header if s.headers.hasKey("Expect"): - if s.headers["Expect"].toLower == "100-continue": + if s.headers["Expect"].toLowerAscii == "100-continue": s.client.sendStatus("100 Continue") else: s.client.sendStatus("417 Expectation Failed") diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim index 685c3b07ac..97223ed019 100644 --- a/lib/pure/matchers.nim +++ b/lib/pure/matchers.nim @@ -29,21 +29,21 @@ proc validEmailAddress*(s: string): bool {.noSideEffect, chars = Letters + Digits + {'!','#','$','%','&', '\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'} var i = 0 - if s[i] notin chars or s[i] == '.': return false - while s[i] in chars: - if s[i] == '.' and s[i+1] == '.': return false + if i >= s.len or s[i] notin chars or s[i] == '.': return false + while i < s.len and s[i] in chars: + if i+1 < s.len and s[i] == '.' and s[i+1] == '.': return false inc(i) - if s[i] != '@': return false + if i >= s.len or s[i] != '@': return false var j = len(s)-1 - if s[j] notin Letters: return false + if j >= 0 and s[j] notin Letters: return false while j >= i and s[j] in Letters: dec(j) inc(i) # skip '@' - while s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i) - if s[i] != '\0': return false + while i < s.len and s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i) + if i != s.len: return false var x = substr(s, j+1) if len(x) == 2 and x[0] in Letters and x[1] in Letters: return true - case toLower(x) + case toLowerAscii(x) of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name", "aero", "jobs", "museum": return true else: return false diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 4500a163fe..3f01f02853 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1126,7 +1126,7 @@ proc unindent*(s: string, count: Natural, padding: string = " "): string var indentCount = 0 for j in 0..= line.len or line[j .. j + padding.len-1] != padding: indentCount = j break result.add(line[indentCount*padding.len .. ^1]) diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index 3c891c81b5..c38d360263 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -232,10 +232,10 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str raise newException(EInvalidCharacterErr, "Invalid character") # Exceptions if qualifiedName.contains(':'): - let qfnamespaces = qualifiedName.toLower().split(':') + let qfnamespaces = qualifiedName.toLowerAscii().split(':') if isNil(namespaceURI): raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil") - elif qfnamespaces[0] == "xml" and + elif qfnamespaces[0] == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace" and qfnamespaces[1] notin stdattrnames: raise newException(ENamespaceErr, @@ -311,10 +311,10 @@ proc createElement*(doc: PDocument, tagName: string): PElement = proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement = ## Creates an element of the given qualified name and namespace URI. if qualifiedName.contains(':'): - let qfnamespaces = qualifiedName.toLower().split(':') + let qfnamespaces = qualifiedName.toLowerAscii().split(':') if isNil(namespaceURI): raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil") - elif qfnamespaces[0] == "xml" and + elif qfnamespaces[0] == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace" and qfnamespaces[1] notin stdattrnames: raise newException(ENamespaceErr, @@ -533,13 +533,13 @@ proc `prefix=`*(n: PNode, value: string) = if isNil(n.fNamespaceURI): raise newException(ENamespaceErr, "namespaceURI cannot be nil") - elif value.toLower() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace": + elif value.toLowerAscii() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace": raise newException(ENamespaceErr, "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"") - elif value.toLower() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/": + elif value.toLowerAscii() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/": raise newException(ENamespaceErr, "When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"") - elif value.toLower() == "xmlns" and n.fNodeType == AttributeNode: + elif value.toLowerAscii() == "xmlns" and n.fNodeType == AttributeNode: raise newException(ENamespaceErr, "An AttributeNode cannot have a prefix of \"xmlns\"") n.fNodeName = value & ":" & n.fLocalName diff --git a/tests/async/tlambda.nim b/tests/async/tlambda.nim index d187c0d50e..8f570689bc 100644 --- a/tests/async/tlambda.nim +++ b/tests/async/tlambda.nim @@ -1,7 +1,7 @@ # bug 2007 -import asyncdispatch, asyncnet, logging, json, uri, strutils, future +import asyncdispatch, asyncnet, logging, json, uri, strutils, sugar type Builder = ref object @@ -27,7 +27,7 @@ proc newBuild*(onProgress: ProgressCB): Build = result.onProgress = onProgress proc start(build: Build, repo, hash: string) {.async.} = - let path = repo.parseUri().path.toLower() + let path = repo.parseUri().path.toLowerAscii() proc onProgress(builder: Builder, message: string) {.async.} = debug($message) From 87f548c5f4027a0faf57acf0878f7c5db382222c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Apr 2018 02:56:19 +0200 Subject: [PATCH 103/214] make more tests green --- tests/manyloc/keineschweine/dependencies/nake/nakefile.nim | 2 +- tests/manyloc/keineschweine/lib/sg_assets.nim | 2 +- tests/manyloc/nake/nakefile.nim | 4 ++-- tests/method/tsimmeth.nim | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim index bdf2139c94..5490211de5 100644 --- a/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim +++ b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim @@ -7,7 +7,7 @@ task "install", "compile and install nake binary": for index, dir in pairs(path): echo " ", index, ". ", dir echo "Where to install nake binary? (quit with ^C or quit or exit)" - let ans = stdin.readLine().toLower + let ans = stdin.readLine().toLowerAscii var index = 0 case ans of "q", "quit", "x", "exit": diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim index fbc3c9ab8e..c6540a428d 100644 --- a/tests/manyloc/keineschweine/lib/sg_assets.nim +++ b/tests/manyloc/keineschweine/lib/sg_assets.nim @@ -562,7 +562,7 @@ proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord = result.useSound = importSound(data[2], errors, "useSound") - case data[1].str.toLower + case data[1].str.toLowerAscii of "projectile": result.kind = Projectile if data[2]["bullet"].kind == JString: diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim index 97af79a84f..3e8609169b 100644 --- a/tests/manyloc/nake/nakefile.nim +++ b/tests/manyloc/nake/nakefile.nim @@ -88,7 +88,7 @@ task "download", "download game assets": if existsFile(path): echo "The file already exists\n", "[R]emove [M]ove [Q]uit [S]kip Source: ", GameAssets - case stdin.readLine.toLower + case stdin.readLine.toLowerAscii of "r": removeFile path of "m": @@ -120,7 +120,7 @@ task "download", "download game assets": echo "Download binary libs? Only libs for linux are available currently, enjoy the irony.\n", "[Y]es [N]o Source: ", BinLibs - case stdin.readline.toLower + case stdin.readline.toLowerAscii of "y", "yes": discard ## o_O else: diff --git a/tests/method/tsimmeth.nim b/tests/method/tsimmeth.nim index 11ff2674f8..a057c35b7f 100644 --- a/tests/method/tsimmeth.nim +++ b/tests/method/tsimmeth.nim @@ -6,7 +6,7 @@ discard """ import strutils -var x = "hello world!".toLower.toUpper +var x = "hello world!".toLowerAscii.toUpperAscii x.echo() #OUT HELLO WORLD! From 5758ebf02c28e1071036d1dc9ae9e1265c6dc28c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Apr 2018 08:53:31 +0200 Subject: [PATCH 104/214] more fixes for the new string behaviour --- examples/httpserver2.nim | 4 ++-- lib/pure/os.nim | 20 +++++++++----------- lib/pure/pegs.nim | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/examples/httpserver2.nim b/examples/httpserver2.nim index 050684d3e4..1843ff967a 100644 --- a/examples/httpserver2.nim +++ b/examples/httpserver2.nim @@ -107,7 +107,7 @@ proc executeCgi(server: var TServer, client: Socket, path, query: string, dataAvail = recvLine(client, buf) if buf.len == 0: break - var L = toLower(buf) + var L = toLowerAscii(buf) if L.startsWith("content-length:"): var i = len("content-length:") while L[i] in Whitespace: inc(i) @@ -205,7 +205,7 @@ proc acceptRequest(server: var TServer, client: Socket) = client.close() else: when defined(Windows): - var ext = splitFile(path).ext.toLower + var ext = splitFile(path).ext.toLowerAscii if ext == ".exe" or ext == ".cgi": # XXX: extract interpreter information here? cgi = true diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 11be8f0c12..644afee325 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1060,18 +1060,17 @@ proc parseCmdLine*(c: string): seq[string] {. while true: setLen(a, 0) # eat all delimiting whitespace - while c[i] == ' ' or c[i] == '\t' or c[i] == '\l' or c[i] == '\r' : inc(i) + while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i) + if i >= c.len: break when defined(windows): # parse a single argument according to the above rules: - if c[i] == '\0': break var inQuote = false - while true: + while i < c.len: case c[i] - of '\0': break of '\\': var j = i - while c[j] == '\\': inc(j) - if c[j] == '"': + while j < c.len and c[j] == '\\': inc(j) + if j < c.len and c[j] == '"': for k in 1..(j-i) div 2: a.add('\\') if (j-i) mod 2 == 0: i = j @@ -1084,7 +1083,7 @@ proc parseCmdLine*(c: string): seq[string] {. of '"': inc(i) if not inQuote: inQuote = true - elif c[i] == '"': + elif i < c.len and c[i] == '"': a.add(c[i]) inc(i) else: @@ -1102,13 +1101,12 @@ proc parseCmdLine*(c: string): seq[string] {. of '\'', '\"': var delim = c[i] inc(i) # skip ' or " - while c[i] != '\0' and c[i] != delim: + while i < c.len and c[i] != delim: add a, c[i] inc(i) - if c[i] != '\0': inc(i) - of '\0': break + if i < c.len: inc(i) else: - while c[i] > ' ': + while i < c.len and c[i] > ' ': add(a, c[i]) inc(i) add(result, a) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 90a460776f..6d415efd06 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -606,7 +606,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. a, b: Rune result = start while i < len(p.term): - if i >= s.len: + if result >= s.len: result = -1 break fastRuneAt(p.term, i, a) From 8da7656071fa18898ee2d9cbe5faa59ebaf33c88 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 30 Apr 2018 10:53:29 +0200 Subject: [PATCH 105/214] make VM tests green --- lib/pure/strtabs.nim | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 75c5e171d8..adce7a526a 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -29,7 +29,7 @@ type modeCaseSensitive, ## the table is case sensitive modeCaseInsensitive, ## the table is case insensitive modeStyleInsensitive ## the table is style insensitive - KeyValuePair = tuple[key, val: string] + KeyValuePair = tuple[key, val: string, hasValue: bool] KeyValuePairSeq = seq[KeyValuePair] StringTableObj* = object of RootObj counter: int @@ -48,19 +48,19 @@ proc len*(t: StringTableRef): int {.rtlFunc, extern: "nst$1".} = iterator pairs*(t: StringTableRef): tuple[key, value: string] = ## iterates over every (key, value) pair in the table `t`. for h in 0..high(t.data): - if not isNil(t.data[h].key): + if not t.data[h].hasValue: yield (t.data[h].key, t.data[h].val) iterator keys*(t: StringTableRef): string = ## iterates over every key in the table `t`. for h in 0..high(t.data): - if not isNil(t.data[h].key): + if t.data[h].hasValue: yield t.data[h].key iterator values*(t: StringTableRef): string = ## iterates over every value in the table `t`. for h in 0..high(t.data): - if not isNil(t.data[h].key): + if t.data[h].hasValue: yield t.data[h].val type @@ -102,7 +102,7 @@ proc nextTry(h, maxHash: Hash): Hash {.inline.} = proc rawGet(t: StringTableRef, key: string): int = var h: Hash = myhash(t, key) and high(t.data) # start with real hash value - while not isNil(t.data[h].key): + while t.data[h].hasValue: if myCmp(t, t.data[h].key, key): return h h = nextTry(h, high(t.data)) @@ -144,16 +144,17 @@ proc contains*(t: StringTableRef, key: string): bool = proc rawInsert(t: StringTableRef, data: var KeyValuePairSeq, key, val: string) = var h: Hash = myhash(t, key) and high(data) - while not isNil(data[h].key): + while data[h].hasValue: h = nextTry(h, high(data)) data[h].key = key data[h].val = val + data[h].hasValue = true proc enlarge(t: StringTableRef) = var n: KeyValuePairSeq newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(t.data)): - if not isNil(t.data[i].key): rawInsert(t, n, t.data[i].key, t.data[i].val) + if t.data[i].hasValue: rawInsert(t, n, t.data[i].key, t.data[i].val) swap(t.data, n) proc `[]=`*(t: StringTableRef, key, val: string) {.rtlFunc, extern: "nstPut".} = @@ -198,8 +199,7 @@ proc clear*(s: StringTableRef, mode: StringTableMode) = s.counter = 0 s.data.setLen(startSize) for i in 0.. Date: Mon, 30 Apr 2018 11:16:56 +0200 Subject: [PATCH 106/214] make more tests green --- lib/pure/encodings.nim | 2 +- lib/pure/ospaths.nim | 2 +- tests/concepts/tstackconcept.nim | 2 +- tests/stdlib/twchartoutf8.nim | 1 - tests/vm/tcompiletimetable.nim | 1 - 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 5840d443db..731fbbc297 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -36,7 +36,7 @@ when defined(windows): while i < a.len and j < b.len: if a[i] in {'-', '_'}: inc i if b[j] in {'-', '_'}: inc j - if a[i].toLower != b[j].toLower: return false + if i < a.len and j < b.len and a[i].toLowerAscii != b[j].toLowerAscii: return false inc i inc j result = i == a.len and j == b.len diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index aeb4a149e1..ee2b715d3a 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -477,7 +477,7 @@ proc unixToNativePath*(path: string, drive=""): string {. var i = start while i < len(path): # ../../../ --> :::: - if path[i] == '.' and path[i+1] == '.' and path[i+2] == '/': + if i+2 < path.len and path[i] == '.' and path[i+1] == '.' and path[i+2] == '/': # parent directory when defined(macos): if result[high(result)] == ':': diff --git a/tests/concepts/tstackconcept.nim b/tests/concepts/tstackconcept.nim index 2238dacb69..cb8db566d8 100644 --- a/tests/concepts/tstackconcept.nim +++ b/tests/concepts/tstackconcept.nim @@ -31,7 +31,7 @@ type s.pop() is T type ValueType = T - const ValueTypeName = T.name.toUpper + const ValueTypeName = T.name.toUpperAscii proc genericAlgorithm[T](s: var Stack[T], y: T) = static: diff --git a/tests/stdlib/twchartoutf8.nim b/tests/stdlib/twchartoutf8.nim index b2f68ee327..a6602e3e39 100644 --- a/tests/stdlib/twchartoutf8.nim +++ b/tests/stdlib/twchartoutf8.nim @@ -30,7 +30,6 @@ else: result = newString(size) let res = WideCharToMultiByte(CP_UTF8, 0'i32, cast[LPWCSTR](addr(wc[0])), wclen, cstring(result), size, cstring(nil), LPBOOL(nil)) - result[size] = chr(0) doAssert size == res proc testCP(wc: WideCString, lo, hi: int) = diff --git a/tests/vm/tcompiletimetable.nim b/tests/vm/tcompiletimetable.nim index b5b84a7907..e78c06536c 100644 --- a/tests/vm/tcompiletimetable.nim +++ b/tests/vm/tcompiletimetable.nim @@ -4,7 +4,6 @@ discard """ 4:2 Got Hi Got Hey''' - disabled: "true" """ # bug #404 From 4948cf3b4c6690c28ca46ba97b0cf1de178bd894 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Apr 2018 11:54:26 +0200 Subject: [PATCH 107/214] make the build more robust --- compiler/ccgexprs.nim | 11 ++++++++--- compiler/condsyms.nim | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index eb67db2b31..a3a85a3dca 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -909,9 +909,14 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: if optBoundsCheck in p.options: - linefmt(p, cpsStmts, - "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(b), rdLoc(a), lenField(p)) + if ty.kind == tyString and not defined(nimNoZeroTerminator): + linefmt(p, cpsStmts, + "if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", + rdLoc(b), rdLoc(a), lenField(p)) + else: + linefmt(p, cpsStmts, + "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", + rdLoc(b), rdLoc(a), lenField(p)) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: a.r = rfmt(nil, "(*$1)", a.r) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 08dda9b6a8..b1d0ccc7a8 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -115,3 +115,4 @@ proc initDefines*() = defineSymbol("nimSymKind") defineSymbol("nimVmEqIdent") defineSymbol("nimNoNil") + defineSymbol("nimNoZeroTerminator") From 50e1a489c04aaf204b1ead53a0013e1e96145844 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Apr 2018 12:06:59 +0200 Subject: [PATCH 108/214] commands.nim: use let instead of var --- compiler/commands.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 06b487cf04..9f265fd158 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -188,11 +188,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, if i < len(arg) and (arg[i] in {':', '='}): inc(i) else: invalidCmdLineOption(pass, orig, info) if state == wHint: - var x = findStr(msgs.HintsToStr, id) + let x = findStr(msgs.HintsToStr, id) if x >= 0: n = TNoteKind(x + ord(hintMin)) else: localError(info, "unknown hint: " & id) else: - var x = findStr(msgs.WarningsToStr, id) + let x = findStr(msgs.WarningsToStr, id) if x >= 0: n = TNoteKind(x + ord(warnMin)) else: localError(info, "unknown warning: " & id) case substr(arg, i).normalize From 6dbfdecd74de1d8a4b53a095af85169951454a89 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Apr 2018 12:07:12 +0200 Subject: [PATCH 109/214] make msgs.nim more robust --- compiler/msgs.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 5ae2c49700..838735753d 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -474,6 +474,10 @@ const hintMin* = hintSuccess hintMax* = high(TMsgKind) +static: + doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1 + doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1 + type TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints TNoteKinds* = set[TNoteKind] From e53b49d024c01c9740a9cbedd763dc22b6c3e2c2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 Apr 2018 12:54:55 +0200 Subject: [PATCH 110/214] strtabs: fixes stupid typo --- lib/pure/strtabs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index adce7a526a..75f9b42cd0 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -48,7 +48,7 @@ proc len*(t: StringTableRef): int {.rtlFunc, extern: "nst$1".} = iterator pairs*(t: StringTableRef): tuple[key, value: string] = ## iterates over every (key, value) pair in the table `t`. for h in 0..high(t.data): - if not t.data[h].hasValue: + if t.data[h].hasValue: yield (t.data[h].key, t.data[h].val) iterator keys*(t: StringTableRef): string = From 85af8fb74cc06ea6044b8796791d7415d4a5f22f Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 30 Apr 2018 19:50:36 +0200 Subject: [PATCH 111/214] introduce --laxstrings switch for backwards compatibility --- compiler/commands.nim | 1 + compiler/options.nim | 3 ++- doc/advopt.txt | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 06b487cf04..34debbc49b 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -499,6 +499,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; undefSymbol("nimOldNewlines") else: localError(info, errOnOrOffExpectedButXFound, arg) + of "laxstrings": processOnOffSwitch({optLaxStrings}, arg, pass, info) of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info) of "floatchecks": processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info) diff --git a/compiler/options.nim b/compiler/options.nim index a5dfaa81cc..9f56d3f180 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -37,7 +37,8 @@ type # please make sure we have under 32 options # evaluation optPatterns, # en/disable pattern matching optMemTracker, - optHotCodeReloading + optHotCodeReloading, + optLaxStrings TOptions* = set[TOption] TGlobalOption* = enum # **keep binary compatible** diff --git a/doc/advopt.txt b/doc/advopt.txt index d4a4b49613..685c8127d9 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -66,6 +66,8 @@ Advanced options: --excessiveStackTrace:on|off stack traces use full file paths --oldNewlines:on|off turn on|off the old behaviour of "\n" + --laxStrings:on|off when turned on, accessing the zero terminator in + strings is allowed; only for backwards compatibility --skipCfg do not read the general configuration file --skipUserCfg do not read the user's configuration file --skipParentCfg do not read the parent dirs' configuration files From 851d2a266d99a9cca3c320067f6d26fc2f2e3e40 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 30 Apr 2018 19:57:52 +0200 Subject: [PATCH 112/214] introduce --laxStrings:on switch --- changelog.md | 4 +++- compiler/ccgexprs.nim | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 251aca4ab7..2e1795bab5 100644 --- a/changelog.md +++ b/changelog.md @@ -85,7 +85,9 @@ these is ``"" / @[]``. - Accessing the binary zero terminator in Nim's native strings is now invalid. Internally a Nim string still has the trailing zero for - zero-copy interoperability with ``cstring``. + zero-copy interoperability with ``cstring``. Compile your code with the + next switch ``--laxStrings:on`` if you need a transition period. + ### Tool changes diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a3a85a3dca..96f9265f17 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -909,7 +909,7 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: if optBoundsCheck in p.options: - if ty.kind == tyString and not defined(nimNoZeroTerminator): + if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options): linefmt(p, cpsStmts, "if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", rdLoc(b), rdLoc(a), lenField(p)) From 6853793ae993a58a3462771a6f32a043512bc943 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 30 Apr 2018 20:05:20 +0200 Subject: [PATCH 113/214] make tests green again --- tests/manyloc/nake/nake.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim index 1e88fa73b9..728619e471 100644 --- a/tests/manyloc/nake/nake.nim +++ b/tests/manyloc/nake/nake.nim @@ -67,7 +67,7 @@ else: for kind, key, val in getOpt(): case kind of cmdLongOption, cmdShortOption: - case key.tolower + case key.tolowerAscii of "tasks", "t": printTaskList = true else: From d62fe7d5384139ad55277c108bf88c105a3c5d30 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 1 May 2018 09:38:17 +0200 Subject: [PATCH 114/214] update the documentation --- doc/tut1.rst | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index 2dc502fabe..f2251c4637 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -944,12 +944,8 @@ String variables are **mutable**, so appending to a string is possible, and quite efficient. Strings in Nim are both zero-terminated and have a length field. A string's length can be retrieved with the builtin ``len`` procedure; the length never counts the terminating zero. Accessing the -terminating zero is not an error and often leads to simpler code: - -.. code-block:: nim - if s[i] == 'a' and s[i+1] == 'b': - # no need to check whether ``i < len(s)``! - ... +terminating zero is an error, it only exists so that a Nim string can be converted +to a ``cstring`` without doing a copy. The assignment operator for strings copies the string. You can use the ``&`` operator to concatenate strings and ``add`` to append to a string. @@ -960,7 +956,7 @@ enforced. For example, when reading strings from binary files, they are merely a sequence of bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the i-th *unichar*. -String variables are initialized with the empty strings ``""``. +A string variable is initialized with the empty string ``""``. Integers From 82275e3779e266c8b9bedb56a71472367ffc786b Mon Sep 17 00:00:00 2001 From: Dmitry Atamanov Date: Tue, 1 May 2018 20:45:38 +0300 Subject: [PATCH 115/214] Fix renderer's errors (#7742) * Fix renderer's errors * Same for filter_tmpl * var -> let --- compiler/filter_tmpl.nim | 3 ++- compiler/renderer.nim | 12 +++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index a1ba9113c1..51ccb8390a 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -42,7 +42,8 @@ proc newLine(p: var TTmplParser) = proc scanPar(p: var TTmplParser, d: int) = var i = d - while true: + let hi = p.x.len - 1 + while i <= hi: case p.x[i] of '\0': break of '(': inc(p.par) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 11d8e86a72..95a622d4ea 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -175,10 +175,11 @@ proc put(g: var TSrcGen, kind: TTokType, s: string) = proc putComment(g: var TSrcGen, s: string) = if s.isNil: return var i = 0 + let hi = len(s) - 1 var isCode = (len(s) >= 2) and (s[1] != ' ') var ind = g.lineLen var com = "## " - while true: + while i <= hi: case s[i] of '\0': break @@ -201,12 +202,12 @@ proc putComment(g: var TSrcGen, s: string) = # gets too long: # compute length of the following word: var j = i - while s[j] > ' ': inc(j) + while j <= hi and s[j] > ' ': inc(j) if not isCode and (g.lineLen + (j - i) > MaxLineLen): put(g, tkComment, com) optNL(g, ind) com = "## " - while s[i] > ' ': + while i <= hi and s[i] > ' ': add(com, s[i]) inc(i) put(g, tkComment, com) @@ -215,8 +216,9 @@ proc putComment(g: var TSrcGen, s: string) = proc maxLineLength(s: string): int = if s.isNil: return 0 var i = 0 + let hi = len(s) - 1 var lineLen = 0 - while true: + while i <= hi: case s[i] of '\0': break @@ -235,7 +237,7 @@ proc maxLineLength(s: string): int = proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) = var i = 0 - var hi = len(s) - 1 + let hi = len(s) - 1 var str = "" while i <= hi: case s[i] From f89218c8b0bc899e84e39a75e0db85473a529b47 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 2 May 2018 08:27:19 +0200 Subject: [PATCH 116/214] fixes #7730, fixes #7746 --- compiler/ropes.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 89b92b76d0..05d5e840c3 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -188,11 +188,11 @@ iterator leaves*(r: Rope): string = var stack = @[r] while stack.len > 0: var it = stack.pop - while isNil(it.data): + while it.left != nil: + assert it.right != nil stack.add(it.right) it = it.left assert(it != nil) - assert(it.data != nil) yield it.data iterator items*(r: Rope): char = From cc0ca43743f286d93c0e4b7adddecd7bb3e83e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Wed, 2 May 2018 08:54:09 +0200 Subject: [PATCH 117/214] Don't hide overflow/underflow/divbyzero in semfold (#7732) * firstOrd/lastOrd bugfix * Don't hide overflow/underflow/divbyzero in semfold --- compiler/semfold.nim | 96 +++++++++++++++++++++-------- compiler/types.nim | 12 ++-- tests/misc/tsemfold.nim | 23 +++++++ tests/typerel/ttypelessemptyset.nim | 2 +- 4 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 tests/misc/tsemfold.nim diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 6fcc9a0a4b..c4d79a4a3b 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -13,7 +13,7 @@ import strutils, options, ast, astalgo, trees, treetab, nimsets, times, nversion, platform, math, msgs, os, condsyms, idents, renderer, types, - commands, magicsys, saturate + commands, magicsys proc getConstExpr*(m: PSym, n: PNode): PNode # evaluates the constant expression or returns nil if it is no constant @@ -24,6 +24,63 @@ proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode proc newStrNodeT*(strVal: string, n: PNode): PNode +proc checkInRange(n: PNode, res: BiggestInt): bool = + if res in firstOrd(n.typ)..lastOrd(n.typ): + result = true + +proc foldAdd(a, b: BiggestInt, n: PNode): PNode = + let res = a +% b + if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and + checkInRange(n, res): + result = newIntNodeT(res, n) + +proc foldSub*(a, b: BiggestInt, n: PNode): PNode = + let res = a -% b + if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and + checkInRange(n, res): + result = newIntNodeT(res, n) + +proc foldAbs*(a: BiggestInt, n: PNode): PNode = + if a != firstOrd(n.typ): + result = newIntNodeT(a, n) + +proc foldMod*(a, b: BiggestInt, n: PNode): PNode = + if b != 0'i64: + result = newIntNodeT(a mod b, n) + +proc foldModU*(a, b: BiggestInt, n: PNode): PNode = + if b != 0'i64: + result = newIntNodeT(a %% b, n) + +proc foldDiv*(a, b: BiggestInt, n: PNode): PNode = + if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64): + result = newIntNodeT(a div b, n) + +proc foldDivU*(a, b: BiggestInt, n: PNode): PNode = + if b != 0'i64: + result = newIntNodeT(a /% b, n) + +proc foldMul*(a, b: BiggestInt, n: PNode): PNode = + let res = a *% b + let floatProd = toBiggestFloat(a) * toBiggestFloat(b) + let resAsFloat = toBiggestFloat(res) + + # Fast path for normal case: small multiplicands, and no info + # is lost in either method. + if resAsFloat == floatProd and checkInRange(n, res): + return newIntNodeT(res, n) + + # Somebody somewhere lost info. Close enough, or way off? Note + # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). + # The difference either is or isn't significant compared to the + # true value (of which floatProd is a good approximation). + + # abs(diff)/abs(prod) <= 1/32 iff + # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" + if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and + checkInRange(n, res): + return newIntNodeT(res, n) + # implementation proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode = @@ -172,23 +229,22 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away of mToFloat, mToBiggestFloat: result = newFloatNodeT(toFloat(int(getInt(a))), n) + # XXX: Hides overflow/underflow of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n) of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n) - of mAbsI: - if getInt(a) >= 0: result = a - else: result = newIntNodeT(- getInt(a), n) + of mAbsI: result = foldAbs(getInt(a), n) of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64: # byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64 result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n) of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n) of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n) of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n) - of mUnaryLt: result = newIntNodeT(getOrdValue(a) |-| 1, n) - of mSucc: result = newIntNodeT(getOrdValue(a) |+| getInt(b), n) - of mPred: result = newIntNodeT(getOrdValue(a) |-| getInt(b), n) - of mAddI: result = newIntNodeT(getInt(a) |+| getInt(b), n) - of mSubI: result = newIntNodeT(getInt(a) |-| getInt(b), n) - of mMulI: result = newIntNodeT(getInt(a) |*| getInt(b), n) + of mUnaryLt: result = foldSub(getOrdValue(a), 1, n) + of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n) + of mPred: result = foldSub(getOrdValue(a), getInt(b), n) + of mAddI: result = foldAdd(getInt(a), getInt(b), n) + of mSubI: result = foldSub(getInt(a), getInt(b), n) + of mMulI: result = foldMul(getInt(a), getInt(b), n) of mMinI: if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n) else: result = newIntNodeT(getInt(a), n) @@ -211,14 +267,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of tyInt64, tyInt, tyUInt..tyUInt64: result = newIntNodeT(`shr`(getInt(a), getInt(b)), n) else: internalError(n.info, "constant folding for shr") - of mDivI: - let y = getInt(b) - if y != 0: - result = newIntNodeT(`|div|`(getInt(a), y), n) - of mModI: - let y = getInt(b) - if y != 0: - result = newIntNodeT(`|mod|`(getInt(a), y), n) + of mDivI: result = foldDiv(getInt(a), getInt(b), n) + of mModI: result = foldMod(getInt(a), getInt(b), n) of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n) of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n) of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n) @@ -258,14 +308,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n) of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n) of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n) - of mModU: - let y = getInt(b) - if y != 0: - result = newIntNodeT(`%%`(getInt(a), y), n) - of mDivU: - let y = getInt(b) - if y != 0: - result = newIntNodeT(`/%`(getInt(a), y), n) + of mModU: result = foldModU(getInt(a), getInt(b), n) + of mDivU: result = foldDivU(getInt(a), getInt(b), n) of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n) of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n) of mLtSet: diff --git a/compiler/types.nim b/compiler/types.nim index 5d60fa9b4e..edf4e5b46b 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -612,13 +612,13 @@ proc firstOrd*(t: PType): BiggestInt = else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position - of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias: + of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic: result = firstOrd(lastSon(t)) of tyOrdinal: if t.len > 0: result = firstOrd(lastSon(t)) - else: internalError("invalid kind for first(" & $t.kind & ')') + else: internalError("invalid kind for firstOrd(" & $t.kind & ')') else: - internalError("invalid kind for first(" & $t.kind & ')') + internalError("invalid kind for firstOrd(" & $t.kind & ')') result = 0 proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt = @@ -651,14 +651,14 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt = of tyEnum: assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) result = t.n.sons[sonsLen(t.n) - 1].sym.position - of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias: + of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic: result = lastOrd(lastSon(t)) of tyProxy: result = 0 of tyOrdinal: if t.len > 0: result = lastOrd(lastSon(t)) - else: internalError("invalid kind for last(" & $t.kind & ')') + else: internalError("invalid kind for lastOrd(" & $t.kind & ')') else: - internalError("invalid kind for last(" & $t.kind & ')') + internalError("invalid kind for lastOrd(" & $t.kind & ')') result = 0 proc lengthOrd*(t: PType): BiggestInt = diff --git a/tests/misc/tsemfold.nim b/tests/misc/tsemfold.nim new file mode 100644 index 0000000000..18c282d9e4 --- /dev/null +++ b/tests/misc/tsemfold.nim @@ -0,0 +1,23 @@ +discard """ + action: run +""" + +doAssertRaises(OverflowError): discard low(int8) - 1'i8 +doAssertRaises(OverflowError): discard high(int8) + 1'i8 +doAssertRaises(OverflowError): discard abs(low(int8)) +doAssertRaises(DivByZeroError): discard 1 mod 0 +doAssertRaises(DivByZeroError): discard 1 div 0 +doAssertRaises(OverflowError): discard low(int8) div -1'i8 + +doAssertRaises(OverflowError): discard low(int64) - 1'i64 +doAssertRaises(OverflowError): discard high(int64) + 1'i64 + +type E = enum eA, eB +doAssertRaises(OverflowError): discard eA.pred +doAssertRaises(OverflowError): discard eB.succ + +doAssertRaises(OverflowError): discard low(int8) * -1 +doAssertRaises(OverflowError): discard low(int64) * -1 +doAssertRaises(OverflowError): discard high(int8) * 2 +doAssertRaises(OverflowError): discard high(int64) * 2 + diff --git a/tests/typerel/ttypelessemptyset.nim b/tests/typerel/ttypelessemptyset.nim index 3e171387b8..5f49c33fdc 100644 --- a/tests/typerel/ttypelessemptyset.nim +++ b/tests/typerel/ttypelessemptyset.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "internal error: invalid kind for last(tyEmpty)" + errormsg: "internal error: invalid kind for lastOrd(tyEmpty)" """ var q = false discard (if q: {} else: {}) From 599b5d6dcbd8b73d98d1aaf2de94d3360229a699 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 1 May 2018 10:48:46 +0200 Subject: [PATCH 118/214] make 'not nil' experimental --- changelog.md | 5 ++++- compiler/condsyms.nim | 1 + compiler/options.nim | 3 ++- compiler/semtypes.nim | 2 ++ lib/system.nim | 2 +- lib/system/excpt.nim | 8 ++++---- tests/notnil/tmust_compile.nim | 1 + tests/notnil/tnotnil.nim | 6 +++--- tests/notnil/tnotnil1.nim | 6 +++--- tests/notnil/tnotnil2.nim | 2 +- tests/notnil/tnotnil3.nim | 2 +- tests/notnil/tnotnil4.nim | 2 ++ tests/notnil/tnotnil_in_generic.nim | 1 + tests/notnil/tnotnil_in_objconstr.nim | 2 +- 14 files changed, 27 insertions(+), 16 deletions(-) diff --git a/changelog.md b/changelog.md index 2e1795bab5..6cd0faf528 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,4 @@ -## v0.X.X - XX/XX/2018 +## v0.19.X - XX/XX/2018 ### Changes affecting backwards compatibility @@ -14,6 +14,9 @@ - Assignments that would "slice" an object into its supertype are now prevented at runtime. Use ``ref object`` with inheritance rather than ``object`` with inheritance to prevent this issue. +- The ``not nil`` type annotation now has to be enabled explicitly + via ``{.experimental: "notnil"}`` as we are still not pleased with how this + feature works with Nim's containers. #### Breaking changes in the standard library diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index b1d0ccc7a8..f8a75e68e3 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -116,3 +116,4 @@ proc initDefines*() = defineSymbol("nimVmEqIdent") defineSymbol("nimNoNil") defineSymbol("nimNoZeroTerminator") + defineSymbol("nimNotNil") diff --git a/compiler/options.nim b/compiler/options.nim index 9f56d3f180..5baaa1bfd5 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -109,7 +109,8 @@ type dotOperators, callOperator, parallel, - destructor + destructor, + notnil ConfigRef* = ref object ## eventually all global configuration should be moved here cppDefines*: HashSet[string] diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 1fc263617b..537319d66f 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1389,6 +1389,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = n.sons[2].kind == nkNilLit: result = freshType(result, prev) result.flags.incl(tfNotNil) + if notnil notin c.features: + localError(n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}") else: localError(n.info, errGenerated, "invalid type") of 2: diff --git a/lib/system.nim b/lib/system.nim index 5c0970f853..0c8659fdaf 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3223,7 +3223,7 @@ when not defined(JS): #and not defined(nimscript): when declared(initGC): initGC() when not defined(nimscript): - proc setControlCHook*(hook: proc () {.noconv.} not nil) + proc setControlCHook*(hook: proc () {.noconv.}) ## allows you to override the behaviour of your application when CTRL+C ## is pressed. Only one such hook is supported. diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index afeab2b6c3..fb38948f7b 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -56,7 +56,7 @@ var # list of exception handlers # a global variable for the root of all try blocks currException {.threadvar.}: ref Exception - raise_counter {.threadvar.}: uint + raise_counter {.threadvar.}: uint gcFramePtr {.threadvar.}: GcFrame @@ -126,10 +126,10 @@ proc popCurrentExceptionEx(id: uint) {.compilerRtl.} = while cur != nil and cur.raise_id != id: prev = cur cur = cur.up - if cur == nil: + if cur == nil: showErrorMessage("popCurrentExceptionEx() exception was not found in the exception stack. Aborting...") quitOrDebug() - prev.up = cur.up + prev.up = cur.up # some platforms have native support for stack traces: const @@ -503,7 +503,7 @@ when not defined(noSignalHandler) and not defined(useNimRtl): registerSignalHandler() # call it in initialization section -proc setControlCHook(hook: proc () {.noconv.} not nil) = +proc setControlCHook(hook: proc () {.noconv.}) = # ugly cast, but should work on all architectures: type SignalHandler = proc (sign: cint) {.noconv, benign.} c_signal(SIGINT, cast[SignalHandler](hook)) diff --git a/tests/notnil/tmust_compile.nim b/tests/notnil/tmust_compile.nim index 10da154f00..a32c6c7ecd 100644 --- a/tests/notnil/tmust_compile.nim +++ b/tests/notnil/tmust_compile.nim @@ -3,6 +3,7 @@ discard """ """ # bug #6682 +{.experimental: "notnil".} type Fields = enum diff --git a/tests/notnil/tnotnil.nim b/tests/notnil/tnotnil.nim index f65634ed66..e392b155c6 100644 --- a/tests/notnil/tnotnil.nim +++ b/tests/notnil/tnotnil.nim @@ -2,7 +2,7 @@ discard """ line: 22 errormsg: "type mismatch" """ - +{.experimental: "notnil".} type PObj = ref TObj not nil TObj = object @@ -15,8 +15,8 @@ type proc p(x: string not nil): int = result = 45 -proc q(x: MyString) = nil -proc q2(x: string) = nil +proc q(x: MyString) = discard +proc q2(x: string) = discard q2(nil) q(nil) diff --git a/tests/notnil/tnotnil1.nim b/tests/notnil/tnotnil1.nim index 73472752c7..7f9d022958 100644 --- a/tests/notnil/tnotnil1.nim +++ b/tests/notnil/tnotnil1.nim @@ -4,7 +4,7 @@ discard """ """ import strutils - +{.experimental: "notnil".} type TObj = object @@ -18,13 +18,13 @@ proc q(s: superstring) = echo s proc p2() = - var a: string = "I am not nil" + var a: string = "I am not nil" q(a) # but this should and does not p2() proc q(x: pointer not nil) = - nil + discard proc p() = var x: pointer diff --git a/tests/notnil/tnotnil2.nim b/tests/notnil/tnotnil2.nim index bd6b8b6755..6ab7bf9519 100644 --- a/tests/notnil/tnotnil2.nim +++ b/tests/notnil/tnotnil2.nim @@ -4,7 +4,7 @@ discard """ """ import strutils - +{.experimental: "notnil".} type TObj = object diff --git a/tests/notnil/tnotnil3.nim b/tests/notnil/tnotnil3.nim index b7c7a811d1..31a4efef78 100644 --- a/tests/notnil/tnotnil3.nim +++ b/tests/notnil/tnotnil3.nim @@ -5,7 +5,7 @@ discard """ # bug #584 # Testprogram for 'not nil' check - +{.experimental: "notnil".} const testWithResult = true type diff --git a/tests/notnil/tnotnil4.nim b/tests/notnil/tnotnil4.nim index 2fa888357f..4fd169827d 100644 --- a/tests/notnil/tnotnil4.nim +++ b/tests/notnil/tnotnil4.nim @@ -2,6 +2,8 @@ discard "" type TObj = ref object +{.experimental: "notnil".} + proc check(a: TObj not nil) = echo repr(a) diff --git a/tests/notnil/tnotnil_in_generic.nim b/tests/notnil/tnotnil_in_generic.nim index 357ab2c7c7..89d20f1826 100644 --- a/tests/notnil/tnotnil_in_generic.nim +++ b/tests/notnil/tnotnil_in_generic.nim @@ -3,6 +3,7 @@ discard """ """ # bug #2216 +{.experimental: "notnil".} type A[T] = ref object diff --git a/tests/notnil/tnotnil_in_objconstr.nim b/tests/notnil/tnotnil_in_objconstr.nim index 7dce98c29f..d33709906b 100644 --- a/tests/notnil/tnotnil_in_objconstr.nim +++ b/tests/notnil/tnotnil_in_objconstr.nim @@ -2,7 +2,7 @@ discard """ errormsg: "fields not initialized: bar" line: "13" """ - +{.experimental: "notnil".} # bug #2355 type Foo = object From 5ac94d26b3691395c40d93109d85fe29d1f14db1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 1 May 2018 11:09:02 +0200 Subject: [PATCH 119/214] remove the deprecated 'nil' statement --- compiler/semstmts.nim | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index eafc9ee667..8b466f1da3 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -107,30 +107,23 @@ proc fixNilType(n: PNode) = proc discardCheck(c: PContext, result: PNode) = if c.matchedConcept != nil: return if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}: - if result.kind == nkNilLit: - result.typ = nil - message(result.info, warnNilStatement) - elif implicitlyDiscardable(result): + if implicitlyDiscardable(result): var n = result result.typ = nil while n.kind in skipForDiscardable: n = n.lastSon n.typ = nil elif result.typ.kind != tyError and gCmd != cmdInteractive: - if result.typ.kind == tyNil: - fixNilType(result) - message(result.info, warnNilStatement) - else: - var n = result - while n.kind in skipForDiscardable: n = n.lastSon - var s = "expression '" & $n & "' is of type '" & - result.typ.typeToString & "' and has to be discarded" - if result.info.line != n.info.line or - result.info.fileIndex != n.info.fileIndex: - s.add "; start of expression here: " & $result.info - if result.typ.kind == tyProc: - s.add "; for a function call use ()" - localError(n.info, s) + var n = result + while n.kind in skipForDiscardable: n = n.lastSon + var s = "expression '" & $n & "' is of type '" & + result.typ.typeToString & "' and has to be discarded" + if result.info.line != n.info.line or + result.info.fileIndex != n.info.fileIndex: + s.add "; start of expression here: " & $result.info + if result.typ.kind == tyProc: + s.add "; for a function call use ()" + localError(n.info, s) proc semIf(c: PContext, n: PNode): PNode = result = n From 74fe7a800b0c2ade3260b8a2f7bc72ea4fd8dc03 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 1 May 2018 15:44:23 +0200 Subject: [PATCH 120/214] make tests green again --- lib/system/embedded.nim | 2 +- .../trecursive_generic_in_compiles.nim | 4 +- tests/constructors/tinvalid_construction.nim | 4 +- tests/converter/tconvert.nim | 2 +- tests/effects/teffects4.nim | 2 +- .../dependencies/chipmunk/chipmunk.nim | 26 +++--- .../keineschweine/dependencies/enet/enet.nim | 22 ++--- .../dependencies/genpacket/genpacket_enet.nim | 14 +-- .../dependencies/genpacket/macro_dsl.nim | 8 +- tests/manyloc/keineschweine/lib/estreams.nim | 2 +- .../keineschweine/lib/input_helpers.nim | 6 +- tests/manyloc/keineschweine/lib/sg_assets.nim | 88 +++++++++---------- .../manyloc/keineschweine/lib/sg_packets.nim | 6 +- tests/metatype/tbindtypedesc.nim | 8 +- tests/notnil/tnotnil2.nim | 2 +- tests/objvariant/tcheckedfield1.nim | 2 +- tests/overload/tissue966.nim | 2 +- tests/proc/tprocredef.nim | 4 +- tests/range/tsubrange.nim | 2 +- 19 files changed, 103 insertions(+), 103 deletions(-) diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim index a14f43e7e6..46e84e0569 100644 --- a/lib/system/embedded.nim +++ b/lib/system/embedded.nim @@ -40,4 +40,4 @@ proc reraiseException() {.compilerRtl.} = proc writeStackTrace() = discard -proc setControlCHook(hook: proc () {.noconv.} not nil) = discard +proc setControlCHook(hook: proc () {.noconv.}) = discard diff --git a/tests/compiles/trecursive_generic_in_compiles.nim b/tests/compiles/trecursive_generic_in_compiles.nim index 77bf0bb027..9c7fd10b31 100644 --- a/tests/compiles/trecursive_generic_in_compiles.nim +++ b/tests/compiles/trecursive_generic_in_compiles.nim @@ -1,6 +1,6 @@ # bug #3313 -import unittest, future - +import unittest, sugar +{.experimental: "notnil".} type ListNodeKind = enum lnkNil, lnkCons diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim index bb3b1bebb9..b3e56eec60 100644 --- a/tests/constructors/tinvalid_construction.nim +++ b/tests/constructors/tinvalid_construction.nim @@ -3,12 +3,12 @@ template accept(x) = template reject(x) = static: assert(not compiles(x)) - +{.experimental: "notnil".} type TRefObj = ref object x: int - THasNotNils = object of TObject + THasNotNils = object of RootObj a: TRefObj not nil b: TRefObj not nil c: TRefObj diff --git a/tests/converter/tconvert.nim b/tests/converter/tconvert.nim index a371402349..48367a85b1 100644 --- a/tests/converter/tconvert.nim +++ b/tests/converter/tconvert.nim @@ -15,6 +15,6 @@ type TFoo = object converter toPtr*(some: var TFoo): ptr TFoo = (addr some) -proc zoot(x: ptr TFoo) = nil +proc zoot(x: ptr TFoo) = discard var x: Tfoo zoot(x) diff --git a/tests/effects/teffects4.nim b/tests/effects/teffects4.nim index fd5dd49e24..d0960126f1 100644 --- a/tests/effects/teffects4.nim +++ b/tests/effects/teffects4.nim @@ -12,7 +12,7 @@ type EIO2 = ref object of EIO proc q() {.tags: [FIO].} = - nil + discard proc raiser(): int = writeLine stdout, "arg" diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim index f06c4e0be3..ac425c7a0a 100644 --- a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim +++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim @@ -388,13 +388,13 @@ type cdecl.} ##cp property emulators -template defGetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} = +template defGetter(otype: typedesc, memberType: typedesc, memberName, procName: untyped) = proc `get procName`*(obj: otype): memberType {.cdecl.} = return obj.memberName -template defSetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} = +template defSetter(otype: typedesc, memberType: typedesc, memberName, procName: untyped) = proc `set procName`*(obj: otype, value: memberType) {.cdecl.} = obj.memberName = value -template defProp(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} = +template defProp(otype: typedesc, memberType: typedesc, memberName, procName: untyped) = defGetter(otype, memberType, memberName, procName) defSetter(otype, memberType, memberName, procName) @@ -908,7 +908,7 @@ proc getShapes*(arb: PArbiter, a, b: var PShape) {.inline.} = #/ A macro shortcut for defining and retrieving the shapes from an arbiter. #define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b); -template getShapes*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} = +template getShapes*(arb: PArbiter, name1, name2: untyped) = var name1, name2: PShape getShapes(arb, name1, name2) @@ -923,7 +923,7 @@ template getShapes*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} = #/ A macro shortcut for defining and retrieving the bodies from an arbiter. #define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b); -template getBodies*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} = +template getBodies*(arb: PArbiter, name1, name2: untyped) = var name1, name2: PBOdy getBodies(arb, name1, name2) @@ -947,11 +947,11 @@ proc getDepth*(arb: PArbiter; i: cint): CpFloat {. cdecl, importc: "cpArbiterGetDepth", dynlib: Lib.} ##Shapes -template defShapeSetter(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} = +template defShapeSetter(memberType: typedesc, memberName: untyped, procName: untyped, activates: bool) = proc `set procName`*(obj: PShape, value: memberType) {.cdecl.} = if activates and obj.body != nil: obj.body.activate() obj.memberName = value -template defShapeProp(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} = +template defShapeProp(memberType: typedesc, memberName: untyped, procName: untyped, activates: bool) = defGetter(PShape, memberType, memberName, procName) defShapeSetter(memberType, memberName, procName, activates) @@ -1272,11 +1272,11 @@ proc activateBodies(constraint: PConstraint) {.inline.} = # cpConstraintActivateBodies(constraint); \ # constraint->member = value; \ # } -template defConstraintSetter(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = +template defConstraintSetter(memberType: typedesc, member, name: untyped) = proc `set name`*(constraint: PConstraint, value: memberType) {.cdecl.} = activateBodies(constraint) constraint.member = value -template defConstraintProp(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = +template defConstraintProp(memberType: typedesc, member, name: untyped) = defGetter(PConstraint, memberType, member, name) defConstraintSetter(memberType, member, name) # CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space) @@ -1306,18 +1306,18 @@ proc getImpulse*(constraint: PConstraint): CpFloat {.inline.} = # cpConstraintActivateBodies(constraint); \ # ((struct *)constraint)->member = value; \ # } -template constraintCheckCast(constraint: PConstraint, ctype: expr): stmt {.immediate.} = +template constraintCheckCast(constraint: PConstraint, ctype: untyped) = assert(constraint.klass == `ctype getClass`(), "Constraint is the wrong class") -template defCGetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = +template defCGetter(ctype: untyped, memberType: typedesc, member, name: untyped) = proc `get ctype name`*(constraint: PConstraint): memberType {.cdecl.} = constraintCheckCast(constraint, ctype) result = cast[`P ctype`](constraint).member -template defCSetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = +template defCSetter(ctype: untyped, memberType: typedesc, member, name: untyped) = proc `set ctype name`*(constraint: PConstraint, value: memberType) {.cdecl.} = constraintCheckCast(constraint, ctype) activateBodies(constraint) cast[`P ctype`](constraint).member = value -template defCProp(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = +template defCProp(ctype: untyped, memberType: typedesc, member, name: untyped) = defCGetter(ctype, memberType, member, name) defCSetter(ctype, memberType, member, name) diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim index 3ea8172d5f..07079f2eaa 100644 --- a/tests/manyloc/keineschweine/dependencies/enet/enet.nim +++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim @@ -24,7 +24,7 @@ const ENET_VERSION_MAJOR* = 1 ENET_VERSION_MINOR* = 3 ENET_VERSION_PATCH* = 3 -template ENET_VERSION_CREATE(major, minor, patch: expr): expr = +template ENET_VERSION_CREATE(major, minor, patch: untyped): untyped = (((major) shl 16) or ((minor) shl 8) or (patch)) const @@ -277,22 +277,22 @@ when defined(Linux) or true: dataLength*: csize TENetSocketSet* = Tfd_set ## see if these are different on win32, if not then get rid of these - template ENET_HOST_TO_NET_16*(value: expr): expr = + template ENET_HOST_TO_NET_16*(value: untyped): untyped = (htons(value)) - template ENET_HOST_TO_NET_32*(value: expr): expr = + template ENET_HOST_TO_NET_32*(value: untyped): untyped = (htonl(value)) - template ENET_NET_TO_HOST_16*(value: expr): expr = + template ENET_NET_TO_HOST_16*(value: untyped): untyped = (ntohs(value)) - template ENET_NET_TO_HOST_32*(value: expr): expr = + template ENET_NET_TO_HOST_32*(value: untyped): untyped = (ntohl(value)) - template ENET_SOCKETSET_EMPTY*(sockset: expr): expr = + template ENET_SOCKETSET_EMPTY*(sockset: untyped): untyped = FD_ZERO(addr((sockset))) - template ENET_SOCKETSET_ADD*(sockset, socket: expr): expr = + template ENET_SOCKETSET_ADD*(sockset, socket: untyped): untyped = FD_SET(socket, addr((sockset))) - template ENET_SOCKETSET_REMOVE*(sockset, socket: expr): expr = + template ENET_SOCKETSET_REMOVE*(sockset, socket: untyped): untyped = FD_CLEAR(socket, addr((sockset))) - template ENET_SOCKETSET_CHECK*(sockset, socket: expr): expr = + template ENET_SOCKETSET_CHECK*(sockset, socket: untyped): untyped = FD_ISSET(socket, addr((sockset))) when defined(Windows): @@ -606,7 +606,7 @@ proc protocolCommandSize*(commandNumber: cuchar): csize{. {.pop.} -from hashes import `!$`, `!&`, THash, hash -proc hash*(x: TAddress): THash {.nimcall, noSideEffect.} = +from hashes import `!$`, `!&`, Hash, hash +proc hash*(x: TAddress): Hash {.nimcall, noSideEffect.} = result = !$(hash(x.host.int32) !& hash(x.port.int16)) diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim index 142b190abb..3fb4dc7d9f 100644 --- a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim +++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim @@ -1,15 +1,15 @@ import macros, macro_dsl, estreams from strutils import format -template newLenName(): stmt {.immediate.} = +template newLenName() = let lenName {.inject.} = ^("len"& $lenNames) inc(lenNames) -template defPacketImports*(): stmt {.immediate, dirty.} = +template defPacketImports*() {.dirty.} = import macros, macro_dsl, estreams from strutils import format -macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = +macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped = result = newNimNode(nnkStmtList) let typeName = quoted2ident(typeNameN) @@ -60,7 +60,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = let name = typeFields[i][0] dotName = packetID.dot(name) - resName = newIdentNode(!"result").dot(name) + resName = newIdentNode("result").dot(name) case typeFields[i][1].kind of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type] case $typeFields[i][1][0].ident @@ -141,7 +141,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = const emptyFields = {nnkEmpty, nnkNilLit} var objFields = newNimNode(nnkRecList) - for i in 0.. < len(typeFields): + for i in 0 ..< len(typeFields): let fname = typeFields[i][0] constructorParams.add(newNimNode(nnkIdentDefs).und( fname, @@ -200,7 +200,7 @@ proc iddefs*(a: string; b: NimNode): NimNode {.compileTime.} = proc varTy*(a: NimNode): NimNode {.compileTime.} = result = newNimNode(nnkVarTy).und(a) -macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} = +macro forwardPacket*(typeName: untyped, underlyingType: untyped): untyped = var packetID = ^"p" streamID = ^"s" @@ -234,7 +234,7 @@ macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} = echo "unknown type:", repr(underlyingtype) echo(repr(result)) -template forwardPacketT*(typeName: expr; underlyingType: expr): stmt {.dirty, immediate.} = +template forwardPacketT*(typeName: untyped; underlyingType: untyped) {.dirty.} = proc `read typeName`*(buffer: PBuffer): typeName = #discard readData(s, addr result, sizeof(result)) var res: underlyingType diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim index 86c12fbb09..33d2a71778 100644 --- a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim +++ b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim @@ -10,7 +10,7 @@ proc und*(a: NimNode; b: varargs[NimNode]): NimNode {.compileTime.} = proc `^`*(a: string): NimNode {.compileTime.} = ## new ident node - result = newIdentNode(!a) + result = newIdentNode(a) proc `[]`*(a, b: NimNode): NimNode {.compileTime.} = ## new bracket expression: node[node] not to be confused with node[indx] result = newNimNode(nnkBracketExpr).und(a, b) @@ -34,7 +34,7 @@ proc emptyNode*(): NimNode {.compileTime.} = proc dot*(left, right: NimNode): NimNode {.compileTime.} = result = newNimNode(nnkDotExpr).und(left, right) proc prefix*(a: string, b: NimNode): NimNode {.compileTime.} = - result = newNimNode(nnkPrefix).und(newIdentNode(!a), b) + result = newNimNode(nnkPrefix).und(newIdentNode(a), b) proc quoted2ident*(a: NimNode): NimNode {.compileTime.} = if a.kind != nnkAccQuoted: @@ -45,13 +45,13 @@ proc quoted2ident*(a: NimNode): NimNode {.compileTime.} = result = ^pname -macro `?`(a: expr): expr = +macro `?`(a: untyped): untyped = ## Character literal ?A #=> 'A' result = ($a[1].ident)[0].lit ## echo(?F,?a,?t,?t,?y) when isMainModule: - macro foo(x: stmt): stmt = + macro foo(x: untyped) = result = newNimNode(nnkStmtList) result.add(newNimNode(nnkCall).und(!!"echo", "Hello thar".lit)) result.add(newCall("echo", lit("3 * 45 = "), (3.lit.infix("*", 45.lit)))) diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim index bdf9b2bf0c..00a55c6263 100644 --- a/tests/manyloc/keineschweine/lib/estreams.nim +++ b/tests/manyloc/keineschweine/lib/estreams.nim @@ -78,7 +78,7 @@ proc write*(buffer: PBuffer; val: var string) = setLen buffer.data, buffer.pos + length.int copyMem(addr buffer.data[buffer.pos], addr val[0], length.int) inc buffer.pos, length.int -proc write*[T: TNumber|bool|char|byte](buffer: PBuffer; val: T) = +proc write*[T: SomeNumber|bool|char|byte](buffer: PBuffer; val: T) = var v: T shallowCopy v, val writeBE buffer, v diff --git a/tests/manyloc/keineschweine/lib/input_helpers.nim b/tests/manyloc/keineschweine/lib/input_helpers.nim index 1953cb58cb..ff1286c8db 100644 --- a/tests/manyloc/keineschweine/lib/input_helpers.nim +++ b/tests/manyloc/keineschweine/lib/input_helpers.nim @@ -5,8 +5,8 @@ type TInputFinishedProc* = proc() TKeyCallback = proc() PKeyClient* = ref object - onKeyDown: TTable[int32, TKeyCallback] - onKeyUp: TTable[int32, TKeyCallback] + onKeyDown: Table[int32, TKeyCallback] + onKeyUp: Table[int32, TKeyCallback] name: string PTextInput* = ref object text*: string @@ -134,5 +134,5 @@ iterator pollEvents*(window: PRenderWindow): PEvent = of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up) of EvtTextEntered: recordText(activeInput, event.text) of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y) - else: nil + else: discard yield(addr event) diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim index c6540a428d..1e8a99c83e 100644 --- a/tests/manyloc/keineschweine/lib/sg_assets.nim +++ b/tests/manyloc/keineschweine/lib/sg_assets.nim @@ -59,7 +59,7 @@ type of Projectile: bullet*: PBulletRecord else: - nil + discard PBulletRecord* = ref TBulletRecord TBulletRecord* = object id*: int16 @@ -115,10 +115,10 @@ var cfg: PZoneSettings SpriteSheets* = initTable[string, PSpriteSheet](64) SoundCache * = initTable[string, PSoundRecord](64) - nameToVehID*: TTable[string, int] - nameToItemID*: TTable[string, int] - nameToObjID*: TTable[string, int] - nameToBulletID*: TTable[string, int] + nameToVehID*: Table[string, int] + nameToItemID*: Table[string, int] + nameToObjID*: Table[string, int] + nameToBulletID*: Table[string, int] activeState = Lobby proc newSprite*(filename: string; errors: var seq[string]): PSpriteSheet @@ -126,7 +126,7 @@ proc load*(ss: PSpriteSheet): bool {.discardable.} proc newSound*(filename: string; errors: var seq[string]): PSoundRecord proc load*(s: PSoundRecord): bool {.discardable.} -proc validateSettings*(settings: PJsonNode; errors: var seq[string]): bool +proc validateSettings*(settings: JsonNode; errors: var seq[string]): bool proc loadSettings*(rawJson: string, errors: var seq[string]): bool proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool @@ -135,17 +135,17 @@ proc fetchItm*(itm: string): PItemRecord proc fetchObj*(name: string): PObjectRecord proc fetchBullet(name: string): PBulletRecord -proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings -proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord -proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord -proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord -proc importPhys(data: PJsonNode): TPhysicsRecord -proc importAnim(data: PJsonNode; errors: var seq[string]): PAnimationRecord -proc importHandling(data: PJsonNode): THandlingRecord -proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord -proc importSoul(data: PJsonNode): TSoulRecord -proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord -proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord +proc importLevel(data: JsonNode; errors: var seq[string]): PLevelSettings +proc importVeh(data: JsonNode; errors: var seq[string]): PVehicleRecord +proc importObject(data: JsonNode; errors: var seq[string]): PObjectRecord +proc importItem(data: JsonNode; errors: var seq[string]): PItemRecord +proc importPhys(data: JsonNode): TPhysicsRecord +proc importAnim(data: JsonNode; errors: var seq[string]): PAnimationRecord +proc importHandling(data: JsonNode): THandlingRecord +proc importBullet(data: JsonNode; errors: var seq[string]): PBulletRecord +proc importSoul(data: JsonNode): TSoulRecord +proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord +proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord ## this is the only pipe between lobby and main.nim proc getActiveState*(): TGameState = @@ -203,7 +203,7 @@ iterator playableVehicles*(): PVehicleRecord = if v.playable: yield v -template allAssets*(body: stmt) {.dirty.}= +template allAssets*(body: untyped) {.dirty.}= block: var assetType = FGraphics for file, asset in pairs(SpriteSheets): @@ -212,7 +212,7 @@ template allAssets*(body: stmt) {.dirty.}= for file, asset in pairs(SoundCache): body -template cacheImpl(procName, cacheName, resultType: expr; body: stmt) {.dirty, immediate.} = +template cacheImpl(procName, cacheName, resultType, body: untyped) {.dirty.} = proc procName*(filename: string; errors: var seq[string]): resulttype = if hasKey(cacheName, filename): return cacheName[filename] @@ -220,7 +220,7 @@ template cacheImpl(procName, cacheName, resultType: expr; body: stmt) {.dirty, i body cacheName[filename] = result -template checkFile(path: expr): stmt {.dirty, immediate.} = +template checkFile(path: untyped) {.dirty.} = if not existsFile(path): errors.add("File missing: "& path) @@ -243,7 +243,7 @@ proc expandPath*(assetType: TAssetType; fileName: string): string = case assetType of FGraphics: result.add "gfx/" of FSound: result.add "sfx/" - else: nil + else: discard result.add fileName proc expandPath*(fc: ScFileChallenge): string {.inline.} = result = expandPath(fc.assetType, fc.file) @@ -280,10 +280,10 @@ else: if not s.soundBuf.isNil: result = true -template addError(e: expr): stmt {.immediate.} = +template addError(e: untyped) = errors.add(e) result = false -proc validateSettings*(settings: PJsonNode, errors: var seq[string]): bool = +proc validateSettings*(settings: JsonNode, errors: var seq[string]): bool = result = true if settings.kind != JObject: addError("Settings root must be an object") @@ -328,10 +328,10 @@ proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool = result = loadSettings(readFile(filename), errors) proc loadSettings*(rawJson: string, errors: var seq[string]): bool = - var settings: PJsonNode + var settings: JsonNode try: settings = parseJson(rawJson) - except EJsonParsingError: + except JsonParsingError: errors.add("JSON parsing error: "& getCurrentExceptionMsg()) return except: @@ -407,21 +407,21 @@ proc fetchObj*(name: string): PObjectRecord = proc fetchBullet(name: string): PBulletRecord = return cfg.bullets[nameToBulletID[name]] -proc getField(node: PJsonNode, field: string, target: var float) = +proc getField(node: JsonNode, field: string, target: var float) = if not node.hasKey(field): return if node[field].kind == JFloat: target = node[field].fnum elif node[field].kind == JInt: target = node[field].num.float -proc getField(node: PJsonNode, field: string, target: var int) = +proc getField(node: JsonNode, field: string, target: var int) = if not node.hasKey(field): return if node[field].kind == JInt: target = node[field].num.int elif node[field].kind == JFloat: target = node[field].fnum.int -proc getField(node: PJsonNode; field: string; target: var bool) = +proc getField(node: JsonNode; field: string; target: var bool) = if not node.hasKey(field): return case node[field].kind @@ -431,19 +431,19 @@ proc getField(node: PJsonNode; field: string; target: var bool) = target = (node[field].num != 0) of JFloat: target = (node[field].fnum != 0.0) - else: nil + else: discard -template checkKey(node: expr; key: string): stmt = +template checkKey(node: untyped; key: string) = if not hasKey(node, key): return -proc importTrail(data: PJsonNode; errors: var seq[string]): TTrailRecord = +proc importTrail(data: JsonNode; errors: var seq[string]): TTrailRecord = checkKey(data, "trail") result.anim = importAnim(data["trail"], errors) result.timer = 1000.0 getField(data["trail"], "timer", result.timer) result.timer /= 1000.0 -proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings = +proc importLevel(data: JsonNode; errors: var seq[string]): PLevelSettings = new(result) result.size = vec2i(5000, 5000) result.starfield = @[] @@ -456,7 +456,7 @@ proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings = if level.hasKey("starfield"): for star in level["starfield"].items: result.starfield.add(newSprite(star.str, errors)) -proc importPhys(data: PJsonNode): TPhysicsRecord = +proc importPhys(data: JsonNode): TPhysicsRecord = result.radius = 20.0 result.mass = 10.0 @@ -466,7 +466,7 @@ proc importPhys(data: PJsonNode): TPhysicsRecord = phys.getField("mass", result.mass) when not defined(NoChipmunk): result.moment = momentForCircle(result.mass, 0.0, result.radius, VectorZero) * MomentMult -proc importHandling(data: PJsonNode): THandlingRecord = +proc importHandling(data: JsonNode): THandlingRecord = result.thrust = 45.0 result.topSpeed = 100.0 #unused result.reverse = 30.0 @@ -483,7 +483,7 @@ proc importHandling(data: PJsonNode): THandlingRecord = hand.getField("reverse", result.reverse) hand.getField("strafe", result.strafe) hand.getField("rotation", result.rotation) -proc importAnim(data: PJsonNode, errors: var seq[string]): PAnimationRecord = +proc importAnim(data: JsonNode, errors: var seq[string]): PAnimationRecord = new(result) result.angle = 0.0 result.delay = 1000.0 @@ -502,26 +502,26 @@ proc importAnim(data: PJsonNode, errors: var seq[string]): PAnimationRecord = result.angle = radians(result.angle) ## comes in as degrees result.delay /= 1000 ## delay comes in as milliseconds -proc importSoul(data: PJsonNode): TSoulRecord = +proc importSoul(data: JsonNode): TSoulRecord = result.energy = 10000 result.health = 1 checkKey(data, "soul") let soul = data["soul"] soul.getField("energy", result.energy) soul.getField("health", result.health) -proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord = +proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord = checkKey(data, "explode") let expl = data["explode"] result.anim = importAnim(expl, errors) result.sound = importSound(expl, errors, "sound") -proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord = +proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord = if data.kind == JObject: checkKey(data, fieldName) result = newSound(data[fieldName].str, errors) elif data.kind == JString: result = newSound(data.str, errors) -proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord = +proc importVeh(data: JsonNode; errors: var seq[string]): PVehicleRecord = new(result) result.playable = false if data.kind != JArray or data.len != 2 or @@ -538,7 +538,7 @@ proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord = vehdata.getField("playable", result.playable) if result.anim.spriteSheet.isNil and result.playable: result.playable = false -proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord = +proc importObject(data: JsonNode; errors: var seq[string]): PObjectRecord = new(result) if data.kind != JArray or data.len != 2: result.name = "(broken)" @@ -546,7 +546,7 @@ proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord = result.name = data[0].str result.anim = importAnim(data[1], errors) result.physics = importPhys(data[1]) -proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord = +proc importItem(data: JsonNode; errors: var seq[string]): PItemRecord = new(result) if data.kind != JArray or data.len != 3: result.name = "(broken)" @@ -576,15 +576,15 @@ proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord = of "ammo": result.kind = Ammo of "utility": - nil + discard else: errors.add "Invalid item type \""&data[1].str&"\" for item "&result.name -proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord = +proc importBullet(data: JsonNode; errors: var seq[string]): PBulletRecord = new(result) result.id = -1 - var bdata: PJsonNode + var bdata: JsonNode if data.kind == JArray: result.name = data[0].str bdata = data[1] diff --git a/tests/manyloc/keineschweine/lib/sg_packets.nim b/tests/manyloc/keineschweine/lib/sg_packets.nim index d84bf72fc4..f3a0e8925c 100644 --- a/tests/manyloc/keineschweine/lib/sg_packets.nim +++ b/tests/manyloc/keineschweine/lib/sg_packets.nim @@ -4,14 +4,14 @@ defPacketImports() type PacketID* = char -template idpacket(pktName, id, s2c, c2s: expr): stmt {.immediate, dirty.} = +template idpacket(pktName, id, s2c, c2s: untyped) {.dirty.} = let `H pktName`* {.inject.} = id defPacket(`Sc pktName`, s2c) defPacket(`Cs pktName`, c2s) forwardPacketT(uint8, int8) forwardPacketT(uint16, int16) -forwardPacketT(TPort, int16) +forwardPacketT(Port, int16) idPacket(Login, 'a', tuple[id: int32; alias: string; sessionKey: string], @@ -22,7 +22,7 @@ defPacket(CsZoneJoinReq, tuple[session: ScLogin]) defPacket(ScZoneRecord, tuple[ name: string = "", desc: string = "", - ip: string = "", port: TPort = 0.Tport]) + ip: string = "", port: Port = 0.Port]) idPacket(ZoneList, 'z', tuple[network: string = "", zones: seq[ScZoneRecord]], tuple[time: string]) diff --git a/tests/metatype/tbindtypedesc.nim b/tests/metatype/tbindtypedesc.nim index b287aad013..039acfbe9e 100644 --- a/tests/metatype/tbindtypedesc.nim +++ b/tests/metatype/tbindtypedesc.nim @@ -46,7 +46,7 @@ type type1 = typedesc type2 = typedesc -proc typePairs(A, B: type1; C, D: type2) = nil +proc typePairs(A, B: type1; C, D: type2) = discard accept typePairs(int, int, TFoo, TFOO) accept typePairs(TBAR, TBar, TBAR, TBAR) @@ -55,7 +55,7 @@ accept typePairs(int, int, string, string) reject typePairs(TBAR, TBar, TBar, TFoo) reject typePairs(string, int, TBAR, TBAR) -proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = nil +proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = discard accept typePairs2(int, int, TFoo, TFOO) accept typePairs2(TBAR, TBar, TBAR, TBAR) @@ -71,12 +71,12 @@ proc dontBind(a: typedesc, b: typedesc) = accept dontBind(int, float) accept dontBind(TFoo, TFoo) -proc dontBind2(a, b: typedesc) = nil +proc dontBind2(a, b: typedesc) = discard accept dontBind2(int, float) accept dontBind2(TBar, int) -proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = nil +proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = discard accept bindArg(int, string, 10, 20, "test", "nest") accept bindArg(int, int, 10, 20, 30, 40) diff --git a/tests/notnil/tnotnil2.nim b/tests/notnil/tnotnil2.nim index 6ab7bf9519..6cd08de734 100644 --- a/tests/notnil/tnotnil2.nim +++ b/tests/notnil/tnotnil2.nim @@ -11,7 +11,7 @@ type x, y: int proc q(x: pointer not nil) = - nil + discard proc p() = var x: pointer diff --git a/tests/objvariant/tcheckedfield1.nim b/tests/objvariant/tcheckedfield1.nim index 56d784a2bd..a7f232c5b3 100644 --- a/tests/objvariant/tcheckedfield1.nim +++ b/tests/objvariant/tcheckedfield1.nim @@ -6,7 +6,7 @@ discard """ import strutils {.warning[ProveField]: on.} - +{.experimental: "notnil".} type TNodeKind = enum nkBinary, nkTernary, nkStr diff --git a/tests/overload/tissue966.nim b/tests/overload/tissue966.nim index c5b28e2176..d0a723875f 100644 --- a/tests/overload/tissue966.nim +++ b/tests/overload/tissue966.nim @@ -5,7 +5,7 @@ discard """ type PTest = ref object -proc test(x: PTest, y: int) = nil +proc test(x: PTest, y: int) = discard var buf: PTest buf.test() diff --git a/tests/proc/tprocredef.nim b/tests/proc/tprocredef.nim index 86ed92b629..4ec7715103 100644 --- a/tests/proc/tprocredef.nim +++ b/tests/proc/tprocredef.nim @@ -4,6 +4,6 @@ discard """ errormsg: "redefinition of \'foo\'" """ -proc foo(a: int, b: string) = nil -proc foo(a: int, b: string) = nil +proc foo(a: int, b: string) = discard +proc foo(a: int, b: string) = discard diff --git a/tests/range/tsubrange.nim b/tests/range/tsubrange.nim index 6f88c5a224..914e7c6e7d 100644 --- a/tests/range/tsubrange.nim +++ b/tests/range/tsubrange.nim @@ -7,7 +7,7 @@ type TRange = range[0..40] proc p(r: TRange) = - nil + discard var r: TRange From 48aee47bf68581d96ced689ced773023081fdffb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 1 May 2018 15:52:50 +0200 Subject: [PATCH 121/214] compiler: code cleanup --- compiler/msgs.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 838735753d..5da375c1c9 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -126,7 +126,7 @@ type warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, warnUnknownSubstitutionX, warnLanguageXNotSupported, warnFieldXNotSupported, warnCommentXIgnored, - warnNilStatement, warnTypelessParam, + warnTypelessParam, warnUseBase, warnWriteToForeignHeap, warnUnsafeCode, warnEachIdentIsTuple, warnShadowIdent, warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, @@ -400,7 +400,6 @@ const warnLanguageXNotSupported: "language \'$1\' not supported", warnFieldXNotSupported: "field \'$1\' not supported", warnCommentXIgnored: "comment \'$1\' ignored", - warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead", warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'", warnUseBase: "use {.base.} for base methods; baseless methods are deprecated", warnWriteToForeignHeap: "write to foreign heap", @@ -451,7 +450,7 @@ const "SmallLshouldNotBeUsed", "UnknownMagic", "RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported", "FieldXNotSupported", - "CommentXIgnored", "NilStmt", + "CommentXIgnored", "TypelessParam", "UseBase", "WriteToForeignHeap", "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", From eb03d9aafe947384440285dfb28be31d2bb1fb0f Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 2 May 2018 09:15:32 +0200 Subject: [PATCH 122/214] fixes #7749 --- lib/pure/strformat.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index abdb655d7c..a8b1284607 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -278,7 +278,7 @@ template callFormatOption(res, arg, option) {.dirty.} = macro `&`*(pattern: string): untyped = ## For a specification of the ``&`` macro, see the module level documentation. if pattern.kind notin {nnkStrLit..nnkTripleStrLit}: - error "& only works with string literals", pattern + error "string formatting (fmt(), &) only works with string literals", pattern let f = pattern.strVal var i = 0 let res = genSym(nskVar, "fmtRes") From 21cbf438ceae059f528cfd28bbeec5b637e210ac Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 2 May 2018 10:51:55 +0200 Subject: [PATCH 123/214] make tests green --- tests/distinct/tnil.nim | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/distinct/tnil.nim b/tests/distinct/tnil.nim index e60437a1f2..759a14657a 100644 --- a/tests/distinct/tnil.nim +++ b/tests/distinct/tnil.nim @@ -1,15 +1,11 @@ discard """ file: "tnil.nim" - output: '''0x1 - -nil - -nil - + output: '''1 +0 +0 ''' - disabled: "windows" """ - +{.experimental: "notnil".} type MyPointer = distinct pointer MyString = distinct string @@ -17,7 +13,8 @@ type MyInt = distinct int proc foo(a: MyPointer) = - echo a.repr + # workaround a Windows 'repr' difference: + echo cast[int](a) foo(cast[MyPointer](1)) foo(cast[MyPointer](nil)) From 452321874d47f33404b68e4624929b7faf02555a Mon Sep 17 00:00:00 2001 From: genotrance Date: Wed, 2 May 2018 12:16:44 -0500 Subject: [PATCH 124/214] Fixes for #7747 - finish.exe issues (#7748) --- tools/finish.nim | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/tools/finish.nim b/tools/finish.nim index 2681f7ccf2..b5ef78b65b 100644 --- a/tools/finish.nim +++ b/tools/finish.nim @@ -52,14 +52,17 @@ when defined(windows): proc askBool(m: string): bool = stdout.write m while true: - let answer = stdin.readLine().normalize - case answer - of "y", "yes": - return true - of "n", "no": - return false - else: - echo "Please type 'y' or 'n'" + try: + let answer = stdin.readLine().normalize + case answer + of "y", "yes": + return true + of "n", "no": + return false + else: + echo "Please type 'y' or 'n'" + except EOFError: + quit(1) proc askNumber(m: string; a, b: int): int = stdout.write m @@ -99,10 +102,6 @@ when defined(windows): proc addToPathEnv*(e: string) = var p = tryGetUnicodeValue(r"Environment", "Path", HKEY_CURRENT_USER) - if p.len == 0: - p = tryGetUnicodeValue( - r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", - "Path", HKEY_LOCAL_MACHINE) let x = if e.contains(Whitespace): "\"" & e & "\"" else: e if p.len > 0: p.add ";" @@ -189,8 +188,10 @@ when defined(windows): proc main() = when defined(windows): let desiredPath = expandFilename(getCurrentDir() / "bin") - let p = getUnicodeValue(r"Environment", "Path", - HKEY_CURRENT_USER) + let p = tryGetUnicodeValue(r"Environment", "Path", + HKEY_CURRENT_USER) & ";" & tryGetUnicodeValue( + r"System\CurrentControlSet\Control\Session Manager\Environment", "Path", + HKEY_LOCAL_MACHINE) var alreadyInPath = false var mingWchoices: seq[string] = @[] var incompat: seq[string] = @[] @@ -199,7 +200,7 @@ proc main() = let y = try: expandFilename(if x[0] == '"' and x[^1] == '"': substr(x, 1, x.len-2) else: x) except: "" - if y == desiredPath: alreadyInPath = true + if y.cmpIgnoreCase(desiredPath) == 0: alreadyInPath = true if y.toLowerAscii.contains("mingw"): if dirExists(y): if checkGccArch(y): mingWchoices.add y From 78e946c4509d9cf02f8508f82dd6daf1fbc168cf Mon Sep 17 00:00:00 2001 From: David Krause Date: Wed, 2 May 2018 23:44:08 +0200 Subject: [PATCH 125/214] fixed high level sendTo for sending to udp6 (#7630) --- lib/pure/net.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ebb59ca6d6..e522d86fef 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1421,8 +1421,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, ## ## **Note:** This proc is not available for SSL sockets. assert(not socket.isClosed, "Cannot `sendTo` on a closed socket") - var aiList = getAddrInfo(address, port, af) - + var aiList = getAddrInfo(address, port, af, socket.sockType, socket.protocol) # try all possibilities: var success = false var it = aiList @@ -1443,7 +1442,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, ## this function will try each IP of that hostname. ## ## This is the high-level version of the above ``sendTo`` function. - result = socket.sendTo(address, port, cstring(data), data.len) + result = socket.sendTo(address, port, cstring(data), data.len, socket.domain ) proc isSsl*(socket: Socket): bool = From 5063437b0ca708ac03b0e27ade65aa3dedf7e73f Mon Sep 17 00:00:00 2001 From: Eugene Kabanov Date: Thu, 3 May 2018 08:53:54 +0300 Subject: [PATCH 126/214] Make clearCallbacks() public. (#7753) --- lib/pure/asyncfutures.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 6df6527d59..8fedb16fe9 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -177,7 +177,7 @@ proc fail*[T](future: Future[T], error: ref Exception) = if getStackTrace(error) == "": getStackTrace() else: getStackTrace(error) future.callbacks.call() -proc clearCallbacks(future: FutureBase) = +proc clearCallbacks*(future: FutureBase) = future.callbacks.function = nil future.callbacks.next = nil From 9099ec5d0b2b8882edaa1bb66c38c99701a59ddc Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 3 May 2018 15:18:19 +0100 Subject: [PATCH 127/214] Merges #7700 manually and adds decodePlus option to decodeUrl too. --- lib/pure/uri.nim | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 9bf25b86b4..36ab00580f 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -47,25 +47,36 @@ proc add*(url: var Url, a: Url) {.deprecated.} = url = url / a {.pop.} -proc encodeUrl*(s: string): string = - ## Encodes a value to be HTTP safe: This means that characters in the set - ## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result, - ## a space is converted to ``'+'`` and every other character is encoded as - ## ``'%xx'`` where ``xx`` denotes its hexadecimal value. +proc encodeUrl*(s: string, usePlus=true): string = + ## Encodes a URL according to RFC3986. + ## + ## This means that characters in the set + ## ``{'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~'}`` are + ## carried over to the result. + ## All other characters are encoded as ``''%xx'`` where ``xx`` + ## denotes its hexadecimal value. + ## + ## As a special rule, when the value of ``usePlus`` is true, + ## spaces are encoded as ``'+'`` instead of ``'%20'``. result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars - for i in 0..s.len-1: - case s[i] - of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i]) - of ' ': add(result, '+') + let fromSpace = if usePlus: "+" else: "%20" + for c in s: + case c + of 'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~': add(result, c) + of ' ': add(result, fromSpace) else: add(result, '%') - add(result, toHex(ord(s[i]), 2)) + add(result, toHex(ord(c), 2)) -proc decodeUrl*(s: string): string = - ## Decodes a value from its HTTP representation: This means that a ``'+'`` - ## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal - ## value) is converted to the character with ordinal number ``xx``, and +proc decodeUrl*(s: string, decodePlus=true): string = + ## Decodes a URL according to RFC3986. + ## + ## This means that any ``'%xx'`` (where ``xx`` denotes a hexadecimal + ## value) are converted to the character with ordinal number ``xx``, ## and every other character is carried over. + ## + ## As a special rule, when the value of ``decodePlus`` is true, ``'+'`` + ## characters are converted to a space. proc handleHexChar(c: char, x: var int) {.inline.} = case c of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) @@ -84,7 +95,11 @@ proc decodeUrl*(s: string): string = handleHexChar(s[i+2], x) inc(i, 2) result[j] = chr(x) - of '+': result[j] = ' ' + of '+': + if decodePlus: + result[j] = ' ' + else: + result[j] = s[i] else: result[j] = s[i] inc(i) inc(j) @@ -370,6 +385,9 @@ when isMainModule: const test1 = "abc\L+def xyz" doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz" doAssert decodeUrl(encodeUrl(test1)) == test1 + doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz" + doAssert decodeUrl(encodeUrl(test1, false), false) == test1 + doAssert decodeUrl(encodeUrl(test1)) == test1 block: let str = "http://localhost" From 9955ee0a9b1a593c7ac6c538264d50bbcd01d42a Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Thu, 3 May 2018 18:15:31 +0300 Subject: [PATCH 128/214] Fixes #7738 --- lib/pure/xmltree.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index a6f62abce7..20bec300f8 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -319,8 +319,8 @@ proc xmlConstructor(a: NimNode): NimNode {.compileTime.} = if a.kind == nnkCall: result = newCall("newXmlTree", toStrLit(a[0])) var attrs = newNimNode(nnkBracket, a) - var newStringTabCall = newCall("newStringTable", attrs, - newIdentNode("modeCaseSensitive")) + var newStringTabCall = newCall(bindSym"newStringTable", attrs, + bindSym"modeCaseSensitive") var elements = newNimNode(nnkBracket, a) for i in 1..a.len-1: if a[i].kind == nnkExprEqExpr: From f94fafff9b6734a82bd252a03ba19057e1913cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Thu, 3 May 2018 17:23:13 +0200 Subject: [PATCH 129/214] Deprecate smart binary search (#7745) * deprecate smartBinarySearch * changelog entry --- changelog.md | 3 +++ lib/pure/algorithm.nim | 32 ++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index 6cd0faf528..336ede15c8 100644 --- a/changelog.md +++ b/changelog.md @@ -63,6 +63,9 @@ fields. - ``system.SomeReal`` is now called ``SomeFloat`` for consistency and correctness. +- ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is + now joined in ``binarySearch``. ``smartbinarySearch`` is now + deprecated. ### Language additions diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 45e031574e..4f7880fec3 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -69,21 +69,25 @@ proc reversed*[T](a: openArray[T]): seq[T] = proc binarySearch*[T](a: openArray[T], key: T): int = ## binary search for `key` in `a`. Returns -1 if not found. - var b = len(a) - while result < b: - var mid = (result + b) div 2 - if a[mid] < key: result = mid + 1 - else: b = mid - if result >= len(a) or a[result] != key: result = -1 + if ((a.len - 1) and a.len) == 0: + # when `a.len` is a power of 2, a faster div can be used. + var step = a.len div 2 + while step > 0: + if a[result or step] <= key: + result = result or step + step = step shr 1 + if a[result] != key: result = -1 + else: + var b = len(a) + while result < b: + var mid = (result + b) div 2 + if a[mid] < key: result = mid + 1 + else: b = mid + if result >= len(a) or a[result] != key: result = -1 -proc smartBinarySearch*[T](a: openArray[T], key: T): int = - ## ``a.len`` must be a power of 2 for this to work. - var step = a.len div 2 - while step > 0: - if a[result or step] <= key: - result = result or step - step = step shr 1 - if a[result] != key: result = -1 +proc smartBinarySearch*[T](a: openArray[T], key: T): int {.deprecated.} = + ## **Deprecated since version 0.18.1**; Use ``binarySearch`` instead. + binarySearch(a,key) const onlySafeCode = true From 8f7bd6cf5ce3772466d90648a182fcd82ded9156 Mon Sep 17 00:00:00 2001 From: notTito Date: Fri, 4 May 2018 08:37:57 +0300 Subject: [PATCH 130/214] Replace factorial function with a compile time one (#7276) * Replace factorial function with a compile time one * Fix the indentation * Update --- lib/pure/math.nim | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index cbd04a145b..5f3240e000 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -29,11 +29,21 @@ proc binom*(n, k: int): int {.noSideEffect.} = for i in countup(2, k): result = (result * (n + 1 - i)) div i -proc fac*(n: int): int {.noSideEffect.} = +proc createFactTable[N: static[int]]: array[N, int] = + result[0] = 1 + for i in 1 ..< N: + result[i] = result[i - 1] * i + +proc fac*(n: int): int = ## Computes the faculty/factorial function. - result = 1 - for i in countup(2, n): - result = result * i + const factTable = + when sizeof(int) == 4: + createFactTable[13]() + else: + createFactTable[21]() + assert(n > 0, $n & " must not be negative.") + assert(n < factTable.len, $n & " is too large to look up in the table") + factTable[n] {.push checks:off, line_dir:off, stack_trace:off.} From 27631b1112bb10e4a7ca43b611c2d3bde2ba320f Mon Sep 17 00:00:00 2001 From: Dmitry Atamanov Date: Fri, 4 May 2018 08:39:05 +0300 Subject: [PATCH 131/214] Fix filter_tmpl errors (#7763) --- compiler/filter_tmpl.nim | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 51ccb8390a..545bea950e 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -45,7 +45,6 @@ proc scanPar(p: var TTmplParser, d: int) = let hi = p.x.len - 1 while i <= hi: case p.x[i] - of '\0': break of '(': inc(p.par) of ')': dec(p.par) of '[': inc(p.bracket) @@ -64,16 +63,22 @@ const proc parseLine(p: var TTmplParser) = var j = 0 - while p.x[j] == ' ': inc(j) + let hi = p.x.len - 1 + + if hi == 0: + return + + while j <= hi and p.x[j] == ' ': inc(j) + if p.x[0] == p.nimDirective and p.x[1] == '?': newLine(p) elif p.x[j] == p.nimDirective: newLine(p) inc(j) - while p.x[j] == ' ': inc(j) + while j <= hi and p.x[j] == ' ': inc(j) let d = j var keyw = "" - while p.x[j] in PatternChars: + while j <= hi and p.x[j] in PatternChars: add(keyw, p.x[j]) inc(j) @@ -127,10 +132,8 @@ proc parseLine(p: var TTmplParser) = llStreamWrite(p.outp, "(\"") inc(p.emitPar) p.state = psTempl - while true: + while j <= hi: case p.x[j] - of '\0': - break of '\x01'..'\x1F', '\x80'..'\xFF': llStreamWrite(p.outp, "\\x") llStreamWrite(p.outp, toHex(ord(p.x[j]), 2)) @@ -157,11 +160,8 @@ proc parseLine(p: var TTmplParser) = llStreamWrite(p.outp, '(') inc(j) var curly = 0 - while true: + while j <= hi: case p.x[j] - of '\0': - localError(p.info, errXExpected, "}") - break of '{': inc(j) inc(curly) @@ -174,6 +174,9 @@ proc parseLine(p: var TTmplParser) = else: llStreamWrite(p.outp, p.x[j]) inc(j) + if curly > 0: + localError(p.info, errXExpected, "}") + break llStreamWrite(p.outp, ')') llStreamWrite(p.outp, p.conc) llStreamWrite(p.outp, '\"') @@ -182,7 +185,7 @@ proc parseLine(p: var TTmplParser) = llStreamWrite(p.outp, p.conc) llStreamWrite(p.outp, p.toStr) llStreamWrite(p.outp, '(') - while p.x[j] in PatternChars: + while j <= hi and p.x[j] in PatternChars: llStreamWrite(p.outp, p.x[j]) inc(j) llStreamWrite(p.outp, ')') From cda591a42f5c3ef29911078c862cb6c07e35f651 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 4 May 2018 07:40:40 +0200 Subject: [PATCH 132/214] Disable setTerminate when noCppExceptions is defined (#7751) --- compiler/cgen.nim | 2 +- lib/system.nim | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index ff3e6714d5..d838f9b9c3 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -265,7 +265,7 @@ proc rdCharLoc(a: TLoc): Rope = proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, takeAddr: bool) = - if p.module.compileToCpp and t.isException: + if p.module.compileToCpp and t.isException and not isDefined("noCppExceptions"): # init vtable in Exception object for polymorphic exceptions includeHeader(p.module, "") linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t)) diff --git a/lib/system.nim b/lib/system.nim index 0c8659fdaf..5781aff273 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -4172,8 +4172,9 @@ template doAssertRaises*(exception, code: untyped): typed = if wrong: raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code)) -when defined(cpp) and appType != "lib" and not defined(js) and - not defined(nimscript) and hostOS != "standalone": +when defined(cpp) and appType != "lib" and + not defined(js) and not defined(nimscript) and + hostOS != "standalone" and not defined(noCppExceptions): proc setTerminate(handler: proc() {.noconv.}) {.importc: "std::set_terminate", header: "".} setTerminate proc() {.noconv.} = From 7d78707e36ca7b7317730244df190b06cf8ddc70 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 4 May 2018 08:10:46 +0200 Subject: [PATCH 133/214] fixes #7766 --- lib/system/sysstr.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index bba59e9309..c5c8a9cac6 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -76,6 +76,7 @@ proc rawNewStringNoInit(space: int): NimString {.compilerProc.} = if s < 7: s = 7 result = allocStrNoInit(sizeof(TGenericSeq) + s + 1) result.reserved = s + result.len = 0 when defined(gogc): result.elemSize = 1 @@ -84,6 +85,7 @@ proc rawNewString(space: int): NimString {.compilerProc.} = if s < 7: s = 7 result = allocStr(sizeof(TGenericSeq) + s + 1) result.reserved = s + result.len = 0 when defined(gogc): result.elemSize = 1 From 6f4ca3f276729bbb99039b823c4227cace3cae92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Fri, 4 May 2018 15:29:21 +0200 Subject: [PATCH 134/214] test binarySearch, fix for search in empty. (#7769) --- lib/pure/algorithm.nim | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 4f7880fec3..5d7348b8dd 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -69,7 +69,7 @@ proc reversed*[T](a: openArray[T]): seq[T] = proc binarySearch*[T](a: openArray[T], key: T): int = ## binary search for `key` in `a`. Returns -1 if not found. - if ((a.len - 1) and a.len) == 0: + if ((a.len - 1) and a.len) == 0 and a.len > 0: # when `a.len` is a power of 2, a faster div can be used. var step = a.len div 2 while step > 0: @@ -367,10 +367,11 @@ when isMainModule: var srt1 = [1,2,3,4,4,4,4,5] var srt2 = ["iello","hello"] var srt3 = [1.0,1.0,1.0] - var srt4: seq[int] = @[] + var srt4: seq[int] assert srt1.isSorted(cmp) == true assert srt2.isSorted(cmp) == false assert srt3.isSorted(cmp) == true + assert srt4.isSorted(cmp) == true var srtseq = newSeq[int]() assert srtseq.isSorted(cmp) == true # Tests for reversed @@ -518,4 +519,24 @@ when isMainModule: block fillEmptySeq: var s = newSeq[int]() - s.fill(0) \ No newline at end of file + s.fill(0) + + block testBinarySearch: + var noData: seq[int] + doAssert binarySearch(noData, 7) == -1 + let oneData = @[1] + doAssert binarySearch(oneData, 1) == 0 + doAssert binarySearch(onedata, 7) == -1 + let someData = @[1,3,4,7] + doAssert binarySearch(someData, 1) == 0 + doAssert binarySearch(somedata, 7) == 3 + doAssert binarySearch(someData, -1) == -1 + doAssert binarySearch(someData, 5) == -1 + doAssert binarySearch(someData, 13) == -1 + let moreData = @[1,3,5,7,4711] + doAssert binarySearch(moreData, -1) == -1 + doAssert binarySearch(moreData, 1) == 0 + doAssert binarySearch(moreData, 5) == 2 + doAssert binarySearch(moreData, 6) == -1 + doAssert binarySearch(moreData, 4711) == 4 + doAssert binarySearch(moreData, 4712) == -1 From 608017801d3625dc8c7991073a0ef84440314c24 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 4 May 2018 22:26:16 +0100 Subject: [PATCH 135/214] Fixes crash in httpclient due to new string indexing rules. --- lib/pure/httpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index b7617b0b50..91b78f59b2 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -749,7 +749,7 @@ proc generateHeaders(requestUrl: Uri, httpMethod: string, if proxy.isNil or requestUrl.scheme == "https": # /path?query - if requestUrl.path[0] != '/': result.add '/' + if not requestUrl.path.startsWith("/"): result.add '/' result.add(requestUrl.path) if requestUrl.query.len > 0: result.add("?" & requestUrl.query) From 805402b294c6cb3ee8e0f39245aa2d1366ae76e9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 14:17:31 +0200 Subject: [PATCH 136/214] fixes #7582 --- compiler/parser.nim | 5 +++-- tests/parser/tcommand_as_expr.nim | 13 ++++++++++++- tests/parser/twrongcmdsyntax.nim | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index ac0a577708..d7a1a75e3b 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -744,8 +744,9 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = # progress guaranteed somePar() result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) - of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType: - if p.inPragma == 0: + of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType, + tkOpr, tkDotDot: + if p.inPragma == 0 and (isUnary(p) or p.tok.tokType notin {tkOpr, tkDotDot}): # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet # solution, but pragmas.nim can't handle that let a = result diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim index a244c87678..b25ec4bd80 100644 --- a/tests/parser/tcommand_as_expr.nim +++ b/tests/parser/tcommand_as_expr.nim @@ -2,7 +2,10 @@ discard """ output: '''140 5-120-120 359 -77''' +77 +-4 +-1 +-1''' """ #import math import sequtils @@ -25,3 +28,11 @@ let a = [2,4,8].map do (d:int) -> int: d + 1 echo a[0], a[1], a[2] echo(foo 8, foo 8) + +# bug #7582 +proc f(x: int): int = x + +echo f -4 + +echo int -1 # doesn't compile +echo int `-` 1 # compiles diff --git a/tests/parser/twrongcmdsyntax.nim b/tests/parser/twrongcmdsyntax.nim index affe72c340..c2962bed44 100644 --- a/tests/parser/twrongcmdsyntax.nim +++ b/tests/parser/twrongcmdsyntax.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''identifier expected, but found 'echo 4''' + errormsg: '''in expression '4 2': identifier expected, but found '4''' line: 6 """ From 1aa359febba7c666c3a0108d6362ac1c51cfaf4e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 14:58:33 +0200 Subject: [PATCH 137/214] warn about inconsistent spacing around binary operators; fixes #7582 --- changelog.md | 5 ++++- compiler/msgs.nim | 6 ++++-- compiler/parser.nim | 8 ++------ compiler/plugins/locals/locals.nim | 2 +- compiler/renderer.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/vmgen.nim | 2 +- lib/pure/algorithm.nim | 2 +- lib/system/assign.nim | 12 ++++++------ lib/system/deepcopy.nim | 10 +++++----- lib/system/gc.nim | 2 +- lib/system/osalloc.nim | 2 +- 12 files changed, 28 insertions(+), 27 deletions(-) diff --git a/changelog.md b/changelog.md index 6cd0faf528..b50bedb5a7 100644 --- a/changelog.md +++ b/changelog.md @@ -17,6 +17,9 @@ - The ``not nil`` type annotation now has to be enabled explicitly via ``{.experimental: "notnil"}`` as we are still not pleased with how this feature works with Nim's containers. +- The parser now warns about inconsistent spacing around binary operators as + these can easily be confused with unary operators. This warning will likely + become an error in the future. #### Breaking changes in the standard library @@ -89,7 +92,7 @@ - Accessing the binary zero terminator in Nim's native strings is now invalid. Internally a Nim string still has the trailing zero for zero-copy interoperability with ``cstring``. Compile your code with the - next switch ``--laxStrings:on`` if you need a transition period. + new switch ``--laxStrings:on`` if you need a transition period. ### Tool changes diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 5da375c1c9..088742d189 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -131,7 +131,7 @@ type warnEachIdentIsTuple, warnShadowIdent, warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, - warnUser, + warnInconsistentSpacing, warnUser, hintSuccess, hintSuccessX, hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, @@ -416,6 +416,7 @@ const warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.", warnLockLevel: "$1", warnResultShadowed: "Special variable 'result' is shadowed.", + warnInconsistentSpacing: "Number of spaces around '$#' is not consistent", warnUser: "$1", hintSuccess: "operation successful", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", @@ -454,7 +455,8 @@ const "TypelessParam", "UseBase", "WriteToForeignHeap", "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", - "GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"] + "GcMem", "Destructor", "LockLevel", "ResultShadowed", + "Spacing", "User"] HintsToStr* = ["Success", "SuccessX", "LineTooLong", "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", diff --git a/compiler/parser.nim b/compiler/parser.nim index d7a1a75e3b..c615195412 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -268,13 +268,9 @@ proc isUnary(p: TParser): bool = proc checkBinary(p: TParser) {.inline.} = ## Check if the current parser token is a binary operator. # we don't check '..' here as that's too annoying - if p.strongSpaces and p.tok.tokType == tkOpr: + if p.tok.tokType == tkOpr: if p.tok.strongSpaceB > 0 and p.tok.strongSpaceA != p.tok.strongSpaceB: - parMessage(p, errGenerated, - "Number of spaces around '$#' not consistent" % - prettyTok(p.tok)) - elif p.tok.strongSpaceA notin {0,1,2,4,8}: - parMessage(p, errGenerated, "Number of spaces must be 0,1,2,4 or 8") + parMessage(p, warnInconsistentSpacing, prettyTok(p.tok)) #| module = stmt ^* (';' / IND{=}) #| diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim index 9cbb611866..ff7f3be581 100644 --- a/compiler/plugins/locals/locals.nim +++ b/compiler/plugins/locals/locals.nim @@ -9,7 +9,7 @@ ## The builtin 'system.locals' implemented as a plugin. -import "../../" / [pluginsupport, ast, astalgo, +import "../../" / [pluginsupport, ast, astalgo, magicsys, lookups, semdata, lowerings] proc semLocals(c: PContext, n: PNode): PNode = diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 95a622d4ea..996168412b 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -342,7 +342,7 @@ proc atom(g: TSrcGen; n: PNode): string = of nkIdent: result = n.ident.s of nkSym: result = n.sym.name.s of nkStrLit: result = ""; result.addQuoted(n.strVal) - of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"' + of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"' of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\"" of nkCharLit: result = "\'" diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 8b466f1da3..f5fdc3445f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -846,7 +846,7 @@ proc checkCovariantParamsUsages(genericType: PType) = if subType != nil: subresult traverseSubTypes(subType) if result: - error("non-invariant type param used in a proc type: " & $t) + error("non-invariant type param used in a proc type: " & $t) of tySequence: return traverseSubTypes(t[0]) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 0544dc311f..f7d3237b8d 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -790,7 +790,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) = elif src.kind in signedIntegers and dst.kind in unsignedIntegers: # cast signed to unsigned integer of same size # unsignedVal = (offset +% signedVal +% 1) and offset - let offset = (1 shl (src_size * 8)) - 1 + let offset = (1 shl (src_size * 8)) - 1 c.gABx(n, opcLdConst, tmp2, mkIntLit(offset)) c.gABx(n, opcLdConst, dest, mkIntLit(offset+1)) c.gABC(n, opcAddu, tmp3, tmp, dest) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 45e031574e..f9a31bc23d 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -395,7 +395,7 @@ proc rotateInternal[T](arg: var openarray[T]; first, middle, last: int): int = swap(arg[mFirst], arg[next]) mFirst += 1 - next += 1 + next += 1 if mFirst == mMiddle: mMiddle = next diff --git a/lib/system/assign.nim b/lib/system/assign.nim index ff1ef31d22..16b56aba7b 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -74,7 +74,7 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = var dst = cast[ByteAddress](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericAssignAux( - cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), + cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize), cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% GenericSeqSize), mt.base, shallow) @@ -100,8 +100,8 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = genericAssignAux(dest, src, mt.node, shallow) of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: - genericAssignAux(cast[pointer](d +% i*% mt.base.size), - cast[pointer](s +% i*% mt.base.size), mt.base, shallow) + genericAssignAux(cast[pointer](d +% i *% mt.base.size), + cast[pointer](s +% i *% mt.base.size), mt.base, shallow) of tyRef: unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[]) of tyOptAsRef: @@ -166,8 +166,8 @@ proc genericAssignOpenArray(dest, src: pointer, len: int, d = cast[ByteAddress](dest) s = cast[ByteAddress](src) for i in 0..len-1: - genericAssign(cast[pointer](d +% i*% mt.base.size), - cast[pointer](s +% i*% mt.base.size), mt.base) + genericAssign(cast[pointer](d +% i *% mt.base.size), + cast[pointer](s +% i *% mt.base.size), mt.base) proc objectInit(dest: pointer, typ: PNimType) {.compilerProc, benign.} proc objectInitAux(dest: pointer, n: ptr TNimNode) {.benign.} = @@ -235,7 +235,7 @@ proc genericReset(dest: pointer, mt: PNimType) = pint[] = nil of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: - genericReset(cast[pointer](d +% i*% mt.base.size), mt.base) + genericReset(cast[pointer](d +% i *% mt.base.size), mt.base) else: zeroMem(dest, mt.size) # set raw bits to zero diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 51e138e5e1..750da00cf1 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -105,7 +105,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = var dst = cast[ByteAddress](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericDeepCopyAux( - cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), + cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize), cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% GenericSeqSize), mt.base, tab) @@ -122,8 +122,8 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = genericDeepCopyAux(dest, src, mt.node, tab) of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: - genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size), - cast[pointer](s +% i*% mt.base.size), mt.base, tab) + genericDeepCopyAux(cast[pointer](d +% i *% mt.base.size), + cast[pointer](s +% i *% mt.base.size), mt.base, tab) of tyRef, tyOptAsRef: let s2 = cast[PPointer](src)[] if s2 == nil: @@ -183,5 +183,5 @@ proc genericDeepCopyOpenArray(dest, src: pointer, len: int, d = cast[ByteAddress](dest) s = cast[ByteAddress](src) for i in 0..len-1: - genericDeepCopy(cast[pointer](d +% i*% mt.base.size), - cast[pointer](s +% i*% mt.base.size), mt.base) + genericDeepCopy(cast[pointer](d +% i *% mt.base.size), + cast[pointer](s +% i *% mt.base.size), mt.base) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 66d49ce1bc..425963f3f9 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -535,7 +535,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), + zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)), newsize-oldsize) sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") # This can be wrong for intermediate temps that are nevertheless on the diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 1ad4cf6952..9609b6d39f 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -58,7 +58,7 @@ when defined(emscripten): # Convert pointer to PageSize correct one. var new_pos = cast[ByteAddress](pos) +% (PageSize - (pos %% PageSize)) - if (new_pos-pos)< sizeof(EmscriptenMMapBlock): + if (new_pos-pos) < sizeof(EmscriptenMMapBlock): new_pos = new_pos +% PageSize result = cast[pointer](new_pos) From eef12654bd896df9b1219ea4bbd6381ccb920e58 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 15:07:13 +0200 Subject: [PATCH 138/214] compiler/msgs.nim: minor code cleanup --- compiler/msgs.nim | 210 +++++++++++++++++++++++----------------------- 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 088742d189..b6cd05e064 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -146,7 +146,7 @@ const errUnknown: "unknown error", errInternal: "internal error: $1", errIllFormedAstX: "illformed AST: $1", - errCannotOpenFile: "cannot open \'$1\'", + errCannotOpenFile: "cannot open '$1'", errGenerated: "$1", errStringLiteralExpected: "string literal expected", errIntLiteralExpected: "integer literal expected", @@ -160,39 +160,39 @@ const errNumberOutOfRange: "number $1 out of valid range", errNnotAllowedInCharacter: "\\n not allowed in character literal", errClosingBracketExpected: "closing ']' expected, but end of file reached", - errMissingFinalQuote: "missing final \' for character literal", - errIdentifierExpected: "identifier expected, but found \'$1\'", - errNewlineExpected: "newline expected, but found \'$1\'", + errMissingFinalQuote: "missing final ' for character literal", + errIdentifierExpected: "identifier expected, but found '$1'", + errNewlineExpected: "newline expected, but found '$1'", errInvalidModuleName: "invalid module name: '$1'", - errOperatorExpected: "operator expected, but found \'$1\'", - errTokenExpected: "\'$1\' expected", - errRecursiveDependencyX: "recursive dependency: \'$1\'", - errOnOrOffExpected: "\'on\' or \'off\' expected", - errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected", + errOperatorExpected: "operator expected, but found '$1'", + errTokenExpected: "'$1' expected", + errRecursiveDependencyX: "recursive dependency: '$1'", + errOnOrOffExpected: "'on' or 'off' expected", + errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected", errInvalidPragma: "invalid pragma", - errUnknownPragma: "unknown pragma: \'$1\'", - errInvalidDirectiveX: "invalid directive: \'$1\'", - errAtPopWithoutPush: "\'pop\' without a \'push\' pragma", + errUnknownPragma: "unknown pragma: '$1'", + errInvalidDirectiveX: "invalid directive: '$1'", + errAtPopWithoutPush: "'pop' without a 'push' pragma", errEmptyAsm: "empty asm statement", errInvalidIndentation: "invalid indentation", errExceptionAlreadyHandled: "exception already handled", errYieldNotAllowedHere: "'yield' only allowed in an iterator", errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator", - errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions", + errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions", errCannotReturnExpr: "current routine cannot return an expression", errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type", - errAttemptToRedefine: "redefinition of \'$1\'", - errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\', \'continue\' or proc call with noreturn pragma", + errAttemptToRedefine: "redefinition of '$1'", + errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma", errStmtExpected: "statement expected", - errInvalidLabel: "\'$1\' is no label", - errInvalidCmdLineOption: "invalid command line option: \'$1\'", - errCmdLineArgExpected: "argument for command line option expected: \'$1\'", - errCmdLineNoArgExpected: "invalid argument for command line option: \'$1\'", - errInvalidVarSubstitution: "invalid variable substitution in \'$1\'", - errUnknownVar: "unknown variable: \'$1\'", - errUnknownCcompiler: "unknown C compiler: \'$1\'", - errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found", - errOnOffOrListExpectedButXFound: "\'on\', \'off\' or \'list\' expected, but \'$1\' found", + errInvalidLabel: "'$1' is no label", + errInvalidCmdLineOption: "invalid command line option: '$1'", + errCmdLineArgExpected: "argument for command line option expected: '$1'", + errCmdLineNoArgExpected: "invalid argument for command line option: '$1'", + errInvalidVarSubstitution: "invalid variable substitution in '$1'", + errUnknownVar: "unknown variable: '$1'", + errUnknownCcompiler: "unknown C compiler: '$1'", + errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found", + errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found", errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found", errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found", errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found", @@ -201,19 +201,19 @@ const errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found", errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected", errInvalidMultipleAsgn: "multiple assignment is not allowed", - errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'", - errExprExpected: "expression expected, but found \'$1\'", - errUndeclaredField: "undeclared field: \'$1\'", - errUndeclaredRoutine: "attempting to call undeclared routine: \'$1\'", - errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier", + errColonOrEqualsExpected: "':' or '=' expected, but found '$1'", + errExprExpected: "expression expected, but found '$1'", + errUndeclaredField: "undeclared field: '$1'", + errUndeclaredRoutine: "attempting to call undeclared routine: '$1'", + errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier", errTypeExpected: "type expected", - errSystemNeeds: "system module needs \'$1\'", + errSystemNeeds: "system module needs '$1'", errExecutionOfProgramFailed: "execution of an external program failed: '$1'", - errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls", - errInvalidArgForX: "invalid argument for \'$1\'", + errNotOverloadable: "overloaded '$1' leads to ambiguous calls", + errInvalidArgForX: "invalid argument for '$1'", errStmtHasNoEffect: "statement has no effect", - errXExpectsTypeOrValue: "\'$1\' expects a type or value", - errXExpectsArrayType: "\'$1\' expects an array type", + errXExpectsTypeOrValue: "'$1' expects a type or value", + errXExpectsArrayType: "'$1' expects an array type", errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", errExprXAmbiguous: "expression '$1' ambiguous in this context", errConstantDivisionByZero: "division by zero", @@ -221,26 +221,26 @@ const errOrdinalOrFloatTypeExpected: "ordinal or float type expected", errOverOrUnderflow: "over- or underflow", errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely", - errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255", - errDynlibRequiresExportc: "\'dynlib\' requires \'exportc\'", - errUndeclaredFieldX: "undeclared field: \'$1\'", + errChrExpectsRange0_255: "'chr' expects an int in the range 0..255", + errDynlibRequiresExportc: "'dynlib' requires 'exportc'", + errUndeclaredFieldX: "undeclared field: '$1'", errNilAccess: "attempt to access a nil address", errIndexOutOfBounds: "index out of bounds", errIndexTypesDoNotMatch: "index types do not match", - errBracketsInvalidForType: "\'[]\' operator invalid for this type", + errBracketsInvalidForType: "'[]' operator invalid for this type", errValueOutOfSetBounds: "value out of set bounds", - errFieldInitTwice: "field initialized twice: \'$1\'", - errFieldNotInit: "field \'$1\' not initialized", - errExprXCannotBeCalled: "expression \'$1\' cannot be called", + errFieldInitTwice: "field initialized twice: '$1'", + errFieldNotInit: "field '$1' not initialized", + errExprXCannotBeCalled: "expression '$1' cannot be called", errExprHasNoType: "expression has no type", - errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)", - errCastNotInSafeMode: "\'cast\' not allowed in safe mode", + errExprXHasNoType: "expression '$1' has no type (or is ambiguous)", + errCastNotInSafeMode: "'cast' not allowed in safe mode", errExprCannotBeCastToX: "expression cannot be cast to $1", errCommaOrParRiExpected: "',' or ')' expected", - errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected", - errSectionExpected: "section (\'type\', \'proc\', etc.) expected", + errCurlyLeOrParLeExpected: "'{' or '(' expected", + errSectionExpected: "section ('type', 'proc', etc.) expected", errRangeExpected: "range expected", - errMagicOnlyInSystem: "\'magic\' only allowed in system module", + errMagicOnlyInSystem: "'magic' only allowed in system module", errPowerOfTwoExpected: "power of two expected", errStringMayNotBeEmpty: "string literal may not be empty", errCallConvExpected: "calling convention expected", @@ -257,51 +257,51 @@ const errWrongNumberOfVariables: "wrong number of variables", errExprCannotBeRaised: "only a 'ref object' can be raised", errBreakOnlyInLoop: "'break' only allowed in loop construct", - errTypeXhasUnknownSize: "type \'$1\' has unknown size", + errTypeXhasUnknownSize: "type '$1' has unknown size", errConstNeedsConstExpr: "a constant can only be initialized with a constant expression", errConstNeedsValue: "a constant needs a value", errResultCannotBeOpenArray: "the result type cannot be on open array", - errSizeTooBig: "computing the type\'s size produced an overflow", + errSizeTooBig: "computing the type's size produced an overflow", errSetTooBig: "set is too large", errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal", errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects", errInheritanceOnlyWithEnums: "inheritance only works with an enum", - errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'", - errCannotInstantiateX: "cannot instantiate: \'$1\'", + errIllegalRecursionInTypeX: "illegal recursion in type '$1'", + errCannotInstantiateX: "cannot instantiate: '$1'", errExprHasNoAddress: "expression has no address", errXStackEscape: "address of '$1' may not escape its stack frame", - errVarForOutParamNeededX: "for a \'var\' type a variable needs to be passed; but '$1' is immutable", + errVarForOutParamNeededX: "for a 'var' type a variable needs to be passed; but '$1' is immutable", errPureTypeMismatch: "type mismatch", errTypeMismatch: "type mismatch: got <", errButExpected: "but expected one of: ", - errButExpectedX: "but expected \'$1\'", + errButExpectedX: "but expected '$1'", errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3", errWrongNumberOfArguments: "wrong number of arguments", errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", - errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar", + errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar", errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", - errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", - errImplOfXexpected: "implementation of \'$1\' expected", + errImplOfXNotAllowed: "implementation of '$1' is not allowed", + errImplOfXexpected: "implementation of '$1' expected", errNoSymbolToBorrowFromFound: "no symbol to borrow from found", errDiscardValueX: "value of type '$1' has to be discarded", errInvalidDiscard: "statement returns no value that can be discarded", errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid", - errCannotBindXTwice: "cannot bind parameter \'$1\' twice", + errCannotBindXTwice: "cannot bind parameter '$1' twice", errInvalidOrderInArrayConstructor: "invalid order in array constructor", - errInvalidOrderInEnumX: "invalid order in enum \'$1\'", - errEnumXHasHoles: "enum \'$1\' has holes", - errExceptExpected: "\'except\' or \'finally\' expected", - errInvalidTry: "after catch all \'except\' or \'finally\' no section may follow", - errOptionExpected: "option expected, but found \'$1\'", - errXisNoLabel: "\'$1\' is not a label", + errInvalidOrderInEnumX: "invalid order in enum '$1'", + errEnumXHasHoles: "enum '$1' has holes", + errExceptExpected: "'except' or 'finally' expected", + errInvalidTry: "after catch all 'except' or 'finally' no section may follow", + errOptionExpected: "option expected, but found '$1'", + errXisNoLabel: "'$1' is not a label", errNotAllCasesCovered: "not all cases are covered", - errUnknownSubstitionVar: "unknown substitution variable: \'$1\'", + errUnknownSubstitionVar: "unknown substitution variable: '$1'", errComplexStmtRequiresInd: "complex statement requires indentation", - errXisNotCallable: "\'$1\' is not callable", + errXisNotCallable: "'$1' is not callable", errNoPragmasAllowedForX: "no pragmas allowed for $1", errNoGenericParamsAllowedForX: "no generic parameters allowed for $1", - errInvalidParamKindX: "invalid param kind: \'$1\'", + errInvalidParamKindX: "invalid param kind: '$1'", errDefaultArgumentInvalid: "default argument invalid", errNamedParamHasToBeIdent: "named parameter has to be an identifier", errNoReturnTypeForX: "no return type allowed for $1", @@ -309,24 +309,24 @@ const errInvalidPragmaX: "invalid pragma: $1", errXNotAllowedHere: "$1 not allowed here", errInvalidControlFlowX: "invalid control flow: $1", - errXisNoType: "invalid type: \'$1\'", + errXisNoType: "invalid type: '$1'", errCircumNeedsPointer: "'[]' needs a pointer or reference type", errInvalidExpression: "invalid expression", - errInvalidExpressionX: "invalid expression: \'$1\'", - errEnumHasNoValueX: "enum has no value \'$1\'", + errInvalidExpressionX: "invalid expression: '$1'", + errEnumHasNoValueX: "enum has no value '$1'", errNamedExprExpected: "named expression expected", errNamedExprNotAllowed: "named expression not allowed here", - errXExpectsOneTypeParam: "\'$1\' expects one type parameter", + errXExpectsOneTypeParam: "'$1' expects one type parameter", errArrayExpectsTwoTypeParams: "array expects two type parameters", - errInvalidVisibilityX: "invalid visibility: \'$1\'", + errInvalidVisibilityX: "invalid visibility: '$1'", errInitHereNotAllowed: "initialization not allowed here", - errXCannotBeAssignedTo: "\'$1\' cannot be assigned to", - errIteratorNotAllowed: "iterators can only be defined at the module\'s top level", + errXCannotBeAssignedTo: "'$1' cannot be assigned to", + errIteratorNotAllowed: "iterators can only be defined at the module's top level", errXNeedsReturnType: "$1 needs a return type", errNoReturnTypeDeclared: "no return type declared", errNoCommand: "no command given", - errInvalidCommandX: "invalid command: \'$1\'", - errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", + errInvalidCommandX: "invalid command: '$1'", + errXOnlyAtModuleScope: "'$1' is only allowed at top level", errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N", errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N", @@ -334,17 +334,17 @@ const errInvalidIndexValueForTuple: "invalid index value for tuple subscript", errCommandExpectsFilename: "command expects a filename argument", errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", - errXExpected: "\'$1\' expected", - errTIsNotAConcreteType: "\'$1\' is not a concrete type.", - errCastToANonConcreteType: "cannot cast to a non concrete type: \'$1\'", + errXExpected: "'$1' expected", + errTIsNotAConcreteType: "'$1' is not a concrete type.", + errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'", errInvalidSectionStart: "invalid section start", errGridTableNotImplemented: "grid table is not implemented", errGeneralParseError: "general parse error", errNewSectionExpected: "new section expected", - errWhitespaceExpected: "whitespace expected, got \'$1\'", - errXisNoValidIndexFile: "\'$1\' is no valid index file", - errCannotRenderX: "cannot render reStructuredText element \'$1\'", - errVarVarTypeNotAllowed: "type \'var var\' is not allowed", + errWhitespaceExpected: "whitespace expected, got '$1'", + errXisNoValidIndexFile: "'$1' is no valid index file", + errCannotRenderX: "cannot render reStructuredText element '$1'", + errVarVarTypeNotAllowed: "type 'var var' is not allowed", errInstantiateXExplicitly: "instantiate '$1' explicitly", errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", @@ -354,26 +354,26 @@ const "A destructor must be associated will all instantiations of a generic type", errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " & "templates, macros and other inline iterators", - errXExpectsTwoArguments: "\'$1\' expects two arguments", - errXExpectsObjectTypes: "\'$1\' expects object types", - errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", + errXExpectsTwoArguments: "'$1' expects two arguments", + errXExpectsObjectTypes: "'$1' expects object types", + errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype", errTooManyIterations: "interpretation requires too many iterations; " & "if you are sure this is not a bug in your code edit " & "compiler/vmdef.MaxLoopIterations and rebuild the compiler", - errCannotInterpretNodeX: "cannot evaluate \'$1\'", - errFieldXNotFound: "field \'$1\' cannot be found", - errInvalidConversionFromTypeX: "invalid conversion from type \'$1\'", + errCannotInterpretNodeX: "cannot evaluate '$1'", + errFieldXNotFound: "field '$1' cannot be found", + errInvalidConversionFromTypeX: "invalid conversion from type '$1'", errAssertionFailed: "assertion failed", - errCannotGenerateCodeForX: "cannot generate code for \'$1\'", + errCannotGenerateCodeForX: "cannot generate code for '$1'", errXRequiresOneArgument: "$1 requires one parameter", errUnhandledExceptionX: "unhandled exception: $1", errCyclicTree: "macro returned a cyclic abstract syntax tree", - errXisNoMacroOrTemplate: "\'$1\' is no macro or template", - errXhasSideEffects: "\'$1\' can have side effects", + errXisNoMacroOrTemplate: "'$1' is no macro or template", + errXhasSideEffects: "'$1' can have side effects", errIteratorExpected: "iterator within for loop context expected", errLetNeedsInit: "'let' symbol requires an initialization", errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread", - errWrongSymbolX: "usage of \'$1\' is a user-defined error", + errWrongSymbolX: "usage of '$1' is a user-defined error", errIllegalCaptureX: "illegal capture '$1'", errXCannotBeClosure: "'$1' cannot have 'closure' calling convention", errXMustBeCompileTime: "'$1' can only be used in compile-time context", @@ -384,22 +384,22 @@ const "it is used as an operand to another routine and the types " & "of the generic paramers can be inferred from the expected signature.", errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.", - errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target", + errCompilerDoesntSupportTarget: "The current compiler '$1' doesn't support the requested compilation target", errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types", errUser: "$1", - warnCannotOpenFile: "cannot open \'$1\'", + warnCannotOpenFile: "cannot open '$1'", warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored", - warnXIsNeverRead: "\'$1\' is never read", - warnXmightNotBeenInit: "\'$1\' might not have been initialized", + warnXIsNeverRead: "'$1' is never read", + warnXmightNotBeenInit: "'$1' might not have been initialized", warnDeprecated: "$1 is deprecated", warnConfigDeprecated: "config file '$1' is deprecated", - warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one)", - warnUnknownMagic: "unknown magic \'$1\' might crash the compiler", - warnRedefinitionOfLabel: "redefinition of label \'$1\'", - warnUnknownSubstitutionX: "unknown substitution \'$1\'", - warnLanguageXNotSupported: "language \'$1\' not supported", - warnFieldXNotSupported: "field \'$1\' not supported", - warnCommentXIgnored: "comment \'$1\' ignored", + warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)", + warnUnknownMagic: "unknown magic '$1' might crash the compiler", + warnRedefinitionOfLabel: "redefinition of label '$1'", + warnUnknownSubstitutionX: "unknown substitution '$1'", + warnLanguageXNotSupported: "language '$1' not supported", + warnFieldXNotSupported: "field '$1' not supported", + warnCommentXIgnored: "comment '$1' ignored", warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'", warnUseBase: "use {.base.} for base methods; baseless methods are deprecated", warnWriteToForeignHeap: "write to foreign heap", @@ -421,15 +421,15 @@ const hintSuccess: "operation successful", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", hintLineTooLong: "line too long", - hintXDeclaredButNotUsed: "\'$1\' is declared but not used", + hintXDeclaredButNotUsed: "'$1' is declared but not used", hintConvToBaseNotNeeded: "conversion to base object is not needed", hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless", - hintExprAlwaysX: "expression evaluates always to \'$1\'", + hintExprAlwaysX: "expression evaluates always to '$1'", hintQuitCalled: "quit() called", hintProcessing: "$1", hintCodeBegin: "generated code listing:", hintCodeEnd: "end of listing", - hintConf: "used config file \'$1\'", + hintConf: "used config file '$1'", hintPath: "added path: '$1'", hintConditionAlwaysTrue: "condition is always true: '$1'", hintName: "name should be: '$1'", From b7116a28eea13f4fd82b8b22323f2f75c813794f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 18:47:29 +0200 Subject: [PATCH 139/214] compiler refactoring, pass config around explicitly --- compiler/docgen.nim | 6 +- compiler/lexer.nim | 35 +- compiler/main.nim | 13 +- compiler/modules.nim | 2 +- compiler/nimconf.nim | 2 +- compiler/options.nim | 1 + compiler/parser.nim | 16 +- compiler/passes.nim | 2 +- compiler/pbraces.nim | 1790 ------------------------------------- compiler/reorder.nim | 8 +- compiler/scriptconfig.nim | 2 +- compiler/sem.nim | 6 +- compiler/semexprs.nim | 6 +- compiler/semstmts.nim | 5 +- compiler/syntaxes.nim | 29 +- compiler/vm.nim | 41 +- compiler/vmdef.nim | 8 +- 17 files changed, 93 insertions(+), 1879 deletions(-) delete mode 100644 compiler/pbraces.nim diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 6f3dcde8b8..e1a70a23e9 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -790,7 +790,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string, discard "fixme: error report" proc commandDoc*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true @@ -840,7 +840,7 @@ proc commandRst2TeX*() = commandRstAux(gProjectFull, TexExt) proc commandJson*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true @@ -855,7 +855,7 @@ proc commandJson*() = writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false) proc commandTags*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 0478ed574c..0aeb44ca3a 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -144,13 +144,12 @@ type cache*: IdentCache when defined(nimsuggest): previousToken: TLineInfo + config*: ConfigRef when defined(nimpretty): var gIndentationWidth*: int -var gLinesCompiled*: int # all lines that have been compiled - proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} = result = newLineInfo(L.fileIdx, tok.line, tok.col) when defined(nimpretty): @@ -222,7 +221,7 @@ proc fillToken(L: var TToken) = L.commentOffsetB = 0 proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; - cache: IdentCache) = + cache: IdentCache; config: ConfigRef) = openBaseLexer(lex, inputstream) lex.fileIdx = fileidx lex.indentAhead = - 1 @@ -231,13 +230,14 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; lex.cache = cache when defined(nimsuggest): lex.previousToken.fileIndex = fileIdx + lex.config = config proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream; - cache: IdentCache) = - openLexer(lex, filename.fileInfoIdx, inputstream, cache) + cache: IdentCache; config: ConfigRef) = + openLexer(lex, filename.fileInfoIdx, inputstream, cache, config) proc closeLexer*(lex: var TLexer) = - inc(gLinesCompiled, lex.lineNumber) + inc(lex.config.linesCompiled, lex.lineNumber) closeBaseLexer(lex) proc getLineInfo(L: TLexer): TLineInfo = @@ -576,17 +576,18 @@ proc getNumber(L: var TLexer, result: var TToken) = result.iNumber = parseBiggestInt(result.literal) # Explicit bounds checks - let outOfRange = case result.tokType: - of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high) - of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or - result.iNumber > BiggestInt(uint8.high)) - of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high) - of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or - result.iNumber > BiggestInt(uint16.high)) - of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high) - of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or - result.iNumber > BiggestInt(uint32.high)) - else: false + let outOfRange = + case result.tokType + of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high) + of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or + result.iNumber > BiggestInt(uint8.high)) + of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high) + of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or + result.iNumber > BiggestInt(uint16.high)) + of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high) + of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or + result.iNumber > BiggestInt(uint32.high)) + else: false if outOfRange: lexMessageLitNum(L, errNumberOutOfRange, startpos) diff --git a/compiler/main.nim b/compiler/main.nim index 401099fc38..f23a3a88e4 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -129,9 +129,10 @@ proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) = interactivePasses(graph, cache) compileSystemModule(graph, cache) let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" - evalNim(graph, echoExp.parseString(cache), makeStdinModule(graph), cache) + evalNim(graph, echoExp.parseString(cache, graph.config), + makeStdinModule(graph), cache) -proc commandScan(cache: IdentCache) = +proc commandScan(cache: IdentCache, config: ConfigRef) = var f = addFileExt(mainCommandArg(), NimExt) var stream = llStreamOpen(f, fmRead) if stream != nil: @@ -139,7 +140,7 @@ proc commandScan(cache: IdentCache) = L: TLexer tok: TToken initToken(tok) - openLexer(L, f, stream, cache) + openLexer(L, f, stream, cache, config) while true: rawGetTok(L, tok) printTok(tok) @@ -265,11 +266,11 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = of "parse": gCmd = cmdParse wantMainModule() - discard parseFile(FileIndex gProjectMainIdx, cache) + discard parseFile(FileIndex gProjectMainIdx, cache, graph.config) of "scan": gCmd = cmdScan wantMainModule() - commandScan(cache) + commandScan(cache, graph.config) msgWriteln("Beware: Indentation tokens depend on the parser's state!") of "secret": gCmd = cmdInteractive @@ -291,7 +292,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = let usedMem = formatSize(getMaxMem()) & " peakmem" else: let usedMem = formatSize(getTotalMem()) - rawMessage(hintSuccessX, [$gLinesCompiled, + rawMessage(hintSuccessX, [$graph.config.linesCompiled, formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3), usedMem, if condSyms.isDefined("release"): "Release Build" diff --git a/compiler/modules.nim b/compiler/modules.nim index 56bfdf662b..7fe2336dd3 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -107,7 +107,7 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = - result = syntaxes.parseFile(fileIdx, cache) + result = syntaxes.parseFile(fileIdx, cache, graph.config) graph.addDep(s, fileIdx) graph.addIncludeDep(s.position.FileIndex, fileIdx) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index bdf5581341..dc8d082b3d 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -205,7 +205,7 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) = stream = llStreamOpen(filename, fmRead) if stream != nil: initToken(tok) - openLexer(L, filename, stream, cache) + openLexer(L, filename, stream, cache, config) tok.tokType = tkEof # to avoid a pointless warning confTok(L, tok, config) # read in the first token while tok.tokType != tkEof: parseAssignment(L, tok, config) diff --git a/compiler/options.nim b/compiler/options.nim index 5baaa1bfd5..f8cb735ae6 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -113,6 +113,7 @@ type notnil ConfigRef* = ref object ## eventually all global configuration should be moved here + linesCompiled*: int # all lines that have been compiled cppDefines*: HashSet[string] headerFile*: string features*: set[Feature] diff --git a/compiler/parser.nim b/compiler/parser.nim index c615195412..14683e3074 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -27,7 +27,7 @@ when isMainModule: outp.close import - llstream, lexer, idents, strutils, ast, astalgo, msgs + llstream, lexer, idents, strutils, ast, astalgo, msgs, options type TParser* = object # A TParser object represents a file that @@ -84,20 +84,20 @@ proc getTok(p: var TParser) = p.hasProgress = true proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, - cache: IdentCache; + cache: IdentCache; config: ConfigRef; strongSpaces=false) = ## Open a parser, using the given arguments to set up its internal state. ## initToken(p.tok) - openLexer(p.lex, fileIdx, inputStream, cache) + openLexer(p.lex, fileIdx, inputStream, cache, config) getTok(p) # read the first token p.firstTok = true p.strongSpaces = strongSpaces proc openParser*(p: var TParser, filename: string, inputStream: PLLStream, - cache: IdentCache; + cache: IdentCache; config: ConfigRef; strongSpaces=false) = - openParser(p, filename.fileInfoIdx, inputStream, cache, strongSpaces) + openParser(p, filename.fileInfoIdx, inputStream, cache, config, strongSpaces) proc closeParser(p: var TParser) = ## Close a parser, freeing up its resources. @@ -2178,8 +2178,8 @@ proc parseTopLevelStmt(p: var TParser): PNode = if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok) break -proc parseString*(s: string; cache: IdentCache; filename: string = ""; - line: int = 0; +proc parseString*(s: string; cache: IdentCache; config: ConfigRef; + filename: string = ""; line: int = 0; errorHandler: TErrorHandler = nil): PNode = ## Parses a string into an AST, returning the top node. ## `filename` and `line`, although optional, provide info so that the @@ -2192,7 +2192,7 @@ proc parseString*(s: string; cache: IdentCache; filename: string = ""; # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong # spaces... parser.lex.errorHandler = errorHandler - openParser(parser, filename, stream, cache, false) + openParser(parser, filename, stream, cache, config, false) result = parser.parseAll closeParser(parser) diff --git a/compiler/passes.nim b/compiler/passes.nim index 6ff3f2bb5d..b104cd132a 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -207,7 +207,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, else: s = stream while true: - openParsers(p, fileIdx, s, cache) + openParsers(p, fileIdx, s, cache, graph.config) if sfSystemModule notin module.flags: # XXX what about caching? no processing then? what if I change the diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim deleted file mode 100644 index fe438d58b6..0000000000 --- a/compiler/pbraces.nim +++ /dev/null @@ -1,1790 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2017 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# This module implements the parser of the braces Nim syntax. - -import - llstream, lexer, idents, strutils, ast, astalgo, msgs - -from parser import TParser - -proc getTok(p: var TParser) = - ## Get the next token from the parser's lexer, and store it in the parser's - ## `tok` member. - rawGetTok(p.lex, p.tok) - -proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream; - cache: IdentCache) = - ## Open a parser, using the given arguments to set up its internal state. - ## - initToken(p.tok) - openLexer(p.lex, fileIdx, inputStream, cache) - getTok(p) # read the first token - p.lex.allowTabs = true - -proc openParser*(p: var TParser, filename: string, inputStream: PLLStream; - cache: IdentCache) = - openParser(p, filename.fileInfoIdx, inputStream, cache) - -proc closeParser*(p: var TParser) = - ## Close a parser, freeing up its resources. - closeLexer(p.lex) - -proc parMessage(p: TParser, msg: TMsgKind, arg = "") = - ## Produce and emit the parser message `arg` to output. - lexMessageTok(p.lex, msg, p.tok, arg) - -proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) = - ## Produce and emit a parser message to output about the token `tok` - parMessage(p, msg, prettyTok(tok)) - -proc rawSkipComment(p: var TParser, node: PNode) = - if p.tok.tokType == tkComment: - if node != nil: - if node.comment == nil: node.comment = "" - add(node.comment, p.tok.literal) - else: - parMessage(p, errInternal, "skipComment") - getTok(p) - -proc skipComment(p: var TParser, node: PNode) = - rawSkipComment(p, node) - -proc flexComment(p: var TParser, node: PNode) = - rawSkipComment(p, node) - -proc skipInd(p: var TParser) = discard -proc optPar(p: var TParser) = discard - -proc optInd(p: var TParser, n: PNode) = - skipComment(p, n) - -proc getTokNoInd(p: var TParser) = - getTok(p) - -proc expectIdentOrKeyw(p: TParser) = - if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType): - lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) - -proc expectIdent(p: TParser) = - if p.tok.tokType != tkSymbol: - lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) - -proc eat(p: var TParser, tokType: TTokType) = - ## Move the parser to the next token if the current token is of type - ## `tokType`, otherwise error. - if p.tok.tokType == tokType: - getTok(p) - else: - lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType]) - -proc parLineInfo(p: TParser): TLineInfo = - ## Retrieve the line information associated with the parser's current state. - result = getLineInfo(p.lex, p.tok) - -proc indAndComment(p: var TParser, n: PNode) = - rawSkipComment(p, n) - -proc newNodeP(kind: TNodeKind, p: TParser): PNode = - result = newNodeI(kind, parLineInfo(p)) - -proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode = - result = newNodeP(kind, p) - result.intVal = intVal - -proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat, - p: TParser): PNode = - result = newNodeP(kind, p) - result.floatVal = floatVal - -proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode = - result = newNodeP(kind, p) - result.strVal = strVal - -proc newIdentNodeP(ident: PIdent, p: TParser): PNode = - result = newNodeP(nkIdent, p) - result.ident = ident - -proc parseExpr(p: var TParser): PNode -proc parseStmt(p: var TParser): PNode -proc parseTypeDesc(p: var TParser): PNode -proc parseDoBlocks(p: var TParser, call: PNode) -proc parseParamList(p: var TParser, retColon = true): PNode -proc parseStmtPragma(p: var TParser): PNode -proc parseCase(p: var TParser): PNode -proc parseTry(p: var TParser): PNode - -proc isSigilLike(tok: TToken): bool {.inline.} = - result = tok.tokType == tkOpr and tok.ident.s[0] == '@' - -proc isAt(tok: TToken): bool {.inline.} = - tok.tokType == tkOpr and tok.ident.s == "@" and tok.strongSpaceB == 0 - -proc isRightAssociative(tok: TToken): bool {.inline.} = - ## Determines whether the token is right assocative. - result = tok.tokType == tkOpr and tok.ident.s[0] == '^' - # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>')) - -proc getPrecedence(tok: TToken): int = - ## Calculates the precedence of the given token. - template considerStrongSpaces(x): untyped = x - - case tok.tokType - of tkOpr: - let L = tok.ident.s.len - let relevantChar = tok.ident.s[0] - - # arrow like? - if L > 1 and tok.ident.s[L-1] == '>' and - tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1) - - template considerAsgn(value: untyped) = - result = if tok.ident.s[L-1] == '=': 1 else: value - - case relevantChar - of '$', '^': considerAsgn(10) - of '*', '%', '/', '\\': considerAsgn(9) - of '~': result = 8 - of '+', '-', '|': considerAsgn(8) - of '&': considerAsgn(7) - of '=', '<', '>', '!': result = 5 - of '.': considerAsgn(6) - of '?': result = 2 - else: considerAsgn(2) - of tkDiv, tkMod, tkShl, tkShr: result = 9 - of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5 - of tkDotDot: result = 6 - of tkAnd: result = 4 - of tkOr, tkXor, tkPtr, tkRef: result = 3 - else: return -10 - result = considerStrongSpaces(result) - -proc isOperator(tok: TToken): bool = - ## Determines if the given token is an operator type token. - tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, - tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor} - -proc isUnary(p: TParser): bool = - ## Check if the current parser token is a unary operator - if p.tok.tokType in {tkOpr, tkDotDot}: - result = true - -proc checkBinary(p: TParser) {.inline.} = - ## Check if the current parser token is a binary operator. - # we don't check '..' here as that's too annoying - discard - -#| module = stmt ^* (';' / IND{=}) -#| -#| comma = ',' COMMENT? -#| semicolon = ';' COMMENT? -#| colon = ':' COMMENT? -#| colcom = ':' COMMENT? -#| -#| operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 -#| | 'or' | 'xor' | 'and' -#| | 'is' | 'isnot' | 'in' | 'notin' | 'of' -#| | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..' -#| -#| prefixOperator = operator -#| -#| optInd = COMMENT? -#| optPar = (IND{>} | IND{=})? -#| -#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)* -#| arrowExpr = assignExpr (OP1 optInd assignExpr)* -#| assignExpr = orExpr (OP2 optInd orExpr)* -#| orExpr = andExpr (OP3 optInd andExpr)* -#| andExpr = cmpExpr (OP4 optInd cmpExpr)* -#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)* -#| sliceExpr = ampExpr (OP6 optInd ampExpr)* -#| ampExpr = plusExpr (OP7 optInd plusExpr)* -#| plusExpr = mulExpr (OP8 optInd mulExpr)* -#| mulExpr = dollarExpr (OP9 optInd dollarExpr)* -#| dollarExpr = primary (OP10 optInd primary)* - -proc colcom(p: var TParser, n: PNode) = - skipComment(p, n) - -proc parseSymbol(p: var TParser, allowNil = false): PNode = - #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' - #| | IDENT | 'addr' | 'type' - case p.tok.tokType - of tkSymbol, tkAddr, tkType: - result = newIdentNodeP(p.tok.ident, p) - getTok(p) - of tkAccent: - result = newNodeP(nkAccQuoted, p) - getTok(p) - while true: - case p.tok.tokType - of tkAccent: - if result.len == 0: - parMessage(p, errIdentifierExpected, p.tok) - break - of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi: - var accm = "" - while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals, - tkParLe..tkParDotRi}: - accm.add(tokToStr(p.tok)) - getTok(p) - result.add(newIdentNodeP(p.lex.cache.getIdent(accm), p)) - of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit: - result.add(newIdentNodeP(p.lex.cache.getIdent(tokToStr(p.tok)), p)) - getTok(p) - else: - parMessage(p, errIdentifierExpected, p.tok) - break - eat(p, tkAccent) - else: - if allowNil and p.tok.tokType == tkNil: - result = newNodeP(nkNilLit, p) - getTok(p) - else: - parMessage(p, errIdentifierExpected, p.tok) - # BUGFIX: We must consume a token here to prevent endless loops! - # But: this really sucks for idetools and keywords, so we don't do it - # if it is a keyword: - if not isKeyword(p.tok.tokType): getTok(p) - result = ast.emptyNode - -proc colonOrEquals(p: var TParser, a: PNode): PNode = - if p.tok.tokType == tkColon: - result = newNodeP(nkExprColonExpr, p) - getTok(p) - #optInd(p, result) - addSon(result, a) - addSon(result, parseExpr(p)) - elif p.tok.tokType == tkEquals: - result = newNodeP(nkExprEqExpr, p) - getTok(p) - #optInd(p, result) - addSon(result, a) - addSon(result, parseExpr(p)) - else: - result = a - -proc exprColonEqExpr(p: var TParser): PNode = - #| exprColonEqExpr = expr (':'|'=' expr)? - var a = parseExpr(p) - result = colonOrEquals(p, a) - -proc exprList(p: var TParser, endTok: TTokType, result: PNode) = - #| exprList = expr ^+ comma - getTok(p) - optInd(p, result) - while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): - var a = parseExpr(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - -proc dotExpr(p: var TParser, a: PNode): PNode = - #| dotExpr = expr '.' optInd symbol - var info = p.parLineInfo - getTok(p) - result = newNodeI(nkDotExpr, info) - optInd(p, result) - addSon(result, a) - addSon(result, parseSymbol(p)) - -proc qualifiedIdent(p: var TParser): PNode = - #| qualifiedIdent = symbol ('.' optInd symbol)? - result = parseSymbol(p) - if p.tok.tokType == tkDot: result = dotExpr(p, result) - -proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = - assert(endTok in {tkCurlyLe, tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) - getTok(p) - optInd(p, result) - while p.tok.tokType != endTok and p.tok.tokType != tkEof: - var a = exprColonEqExpr(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, endTok) - -proc exprColonEqExprList(p: var TParser, kind: TNodeKind, - endTok: TTokType): PNode = - #| exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? - result = newNodeP(kind, p) - exprColonEqExprListAux(p, endTok, result) - -proc setOrTableConstr(p: var TParser): PNode = - result = newNodeP(nkCurly, p) - getTok(p) - optInd(p, result) - if p.tok.tokType == tkColon: - getTok(p) # skip ':' - result.kind = nkTableConstr - else: - while p.tok.tokType notin {tkBracketDotRi, tkEof}: - var a = exprColonEqExpr(p) - if a.kind == nkExprColonExpr: result.kind = nkTableConstr - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkBracketDotRi) - -proc parseCast(p: var TParser): PNode = - #| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' - result = newNodeP(nkCast, p) - getTok(p) - eat(p, tkBracketLe) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - optPar(p) - eat(p, tkBracketRi) - eat(p, tkParLe) - optInd(p, result) - addSon(result, parseExpr(p)) - optPar(p) - eat(p, tkParRi) - -proc setBaseFlags(n: PNode, base: TNumericalBase) = - case base - of base10: discard - of base2: incl(n.flags, nfBase2) - of base8: incl(n.flags, nfBase8) - of base16: incl(n.flags, nfBase16) - -proc parseGStrLit(p: var TParser, a: PNode): PNode = - case p.tok.tokType - of tkGStrLit: - result = newNodeP(nkCallStrLit, p) - addSon(result, a) - addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)) - getTok(p) - of tkGTripleStrLit: - result = newNodeP(nkCallStrLit, p) - addSon(result, a) - addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p)) - getTok(p) - else: - result = a - -type - TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix - -proc complexOrSimpleStmt(p: var TParser): PNode -proc simpleExpr(p: var TParser, mode = pmNormal): PNode - -proc semiStmtList(p: var TParser, result: PNode) = - inc p.inSemiStmtList - result.add(complexOrSimpleStmt(p)) - while p.tok.tokType == tkSemiColon: - getTok(p) - optInd(p, result) - result.add(complexOrSimpleStmt(p)) - dec p.inSemiStmtList - result.kind = nkStmtListExpr - -proc parsePar(p: var TParser): PNode = - #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' - #| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' - #| | 'when' | 'var' | 'mixin' - #| par = '(' optInd - #| ( &parKeyw complexOrSimpleStmt ^+ ';' - #| | ';' complexOrSimpleStmt ^+ ';' - #| | pragmaStmt - #| | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? ) - #| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) ) - #| optPar ')' - # - # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a - # leading ';' could be used to enforce a 'stmt' context ... - result = newNodeP(nkPar, p) - getTok(p) - optInd(p, result) - if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase, - tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock, - tkConst, tkLet, tkWhen, tkVar, - tkMixin}: - # XXX 'bind' used to be an expression, so we exclude it here; - # tests/reject/tbind2 fails otherwise. - semiStmtList(p, result) - elif p.tok.tokType == tkSemiColon: - # '(;' enforces 'stmt' context: - getTok(p) - optInd(p, result) - semiStmtList(p, result) - elif p.tok.tokType == tkCurlyDotLe: - result.add(parseStmtPragma(p)) - elif p.tok.tokType != tkParRi: - var a = simpleExpr(p) - if p.tok.tokType == tkEquals: - # special case: allow assignments - getTok(p) - optInd(p, result) - let b = parseExpr(p) - let asgn = newNodeI(nkAsgn, a.info, 2) - asgn.sons[0] = a - asgn.sons[1] = b - result.add(asgn) - if p.tok.tokType == tkSemiColon: - semiStmtList(p, result) - elif p.tok.tokType == tkSemiColon: - # stmt context: - result.add(a) - semiStmtList(p, result) - else: - a = colonOrEquals(p, a) - result.add(a) - if p.tok.tokType == tkComma: - getTok(p) - skipComment(p, a) - while p.tok.tokType != tkParRi and p.tok.tokType != tkEof: - var a = exprColonEqExpr(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkParRi) - -proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = - #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT - #| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT - #| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT - #| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT - #| | CHAR_LIT - #| | NIL - #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT - #| identOrLiteral = generalizedLit | symbol | literal - #| | par | arrayConstr | setOrTableConstr - #| | castExpr - #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')' - #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']' - case p.tok.tokType - of tkSymbol, tkType, tkAddr: - result = newIdentNodeP(p.tok.ident, p) - getTok(p) - result = parseGStrLit(p, result) - of tkAccent: - result = parseSymbol(p) # literals - of tkIntLit: - result = newIntNodeP(nkIntLit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt8Lit: - result = newIntNodeP(nkInt8Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt16Lit: - result = newIntNodeP(nkInt16Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt32Lit: - result = newIntNodeP(nkInt32Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt64Lit: - result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUIntLit: - result = newIntNodeP(nkUIntLit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt8Lit: - result = newIntNodeP(nkUInt8Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt16Lit: - result = newIntNodeP(nkUInt16Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt32Lit: - result = newIntNodeP(nkUInt32Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt64Lit: - result = newIntNodeP(nkUInt64Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloatLit: - result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloat32Lit: - result = newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloat64Lit: - result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloat128Lit: - result = newFloatNodeP(nkFloat128Lit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkStrLit: - result = newStrNodeP(nkStrLit, p.tok.literal, p) - getTok(p) - of tkRStrLit: - result = newStrNodeP(nkRStrLit, p.tok.literal, p) - getTok(p) - of tkTripleStrLit: - result = newStrNodeP(nkTripleStrLit, p.tok.literal, p) - getTok(p) - of tkCharLit: - result = newIntNodeP(nkCharLit, ord(p.tok.literal[0]), p) - getTok(p) - of tkNil: - result = newNodeP(nkNilLit, p) - getTok(p) - of tkParLe: - # () constructor - if mode in {pmTypeDesc, pmTypeDef}: - result = exprColonEqExprList(p, nkPar, tkParRi) - else: - result = parsePar(p) - of tkBracketDotLe: - # {} constructor - result = setOrTableConstr(p) - of tkBracketLe: - # [] constructor - result = exprColonEqExprList(p, nkBracket, tkBracketRi) - of tkCast: - result = parseCast(p) - else: - parMessage(p, errExprExpected, p.tok) - getTok(p) # we must consume a token here to prevend endless loops! - result = ast.emptyNode - -proc namedParams(p: var TParser, callee: PNode, - kind: TNodeKind, endTok: TTokType): PNode = - let a = callee - result = newNodeP(kind, p) - addSon(result, a) - exprColonEqExprListAux(p, endTok, result) - -proc parseMacroColon(p: var TParser, x: PNode): PNode -proc primarySuffix(p: var TParser, r: PNode): PNode = - #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks? - #| | doBlocks - #| | '.' optInd symbol generalizedLit? - #| | '[' optInd indexExprList optPar ']' - #| | '{' optInd indexExprList optPar '}' - #| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax - result = r - - template somePar() = discard - while p.tok.indent < 0: - case p.tok.tokType - of tkParLe: - somePar() - result = namedParams(p, result, nkCall, tkParRi) - if result.len > 1 and result.sons[1].kind == nkExprColonExpr: - result.kind = nkObjConstr - else: - parseDoBlocks(p, result) - of tkDo: - var a = result - result = newNodeP(nkCall, p) - addSon(result, a) - parseDoBlocks(p, result) - of tkDot: - result = dotExpr(p, result) - result = parseGStrLit(p, result) - of tkBracketLe: - somePar() - result = namedParams(p, result, nkBracketExpr, tkBracketRi) - of tkBracketDotLe: - somePar() - result = namedParams(p, result, nkCurlyExpr, tkBracketDotRi) - of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType: - if p.inPragma == 0: - # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet - # solution, but pragmas.nim can't handle that - let a = result - result = newNodeP(nkCommand, p) - addSon(result, a) - when true: - addSon result, parseExpr(p) - else: - while p.tok.tokType != tkEof: - let x = parseExpr(p) - addSon(result, x) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, x) - if p.tok.tokType == tkDo: - parseDoBlocks(p, result) - else: - result = parseMacroColon(p, result) - break - else: - break - -proc primary(p: var TParser, mode: TPrimaryMode): PNode -proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode - -proc parseOperators(p: var TParser, headNode: PNode, - limit: int, mode: TPrimaryMode): PNode = - result = headNode - # expand while operators have priorities higher than 'limit' - var opPrec = getPrecedence(p.tok) - let modeB = if mode == pmTypeDef: pmTypeDesc else: mode - # the operator itself must not start on a new line: - while opPrec >= limit and p.tok.indent < 0 and not isAt(p.tok): - checkBinary(p) - var leftAssoc = 1-ord(isRightAssociative(p.tok)) - var a = newNodeP(nkInfix, p) - var opNode = newIdentNodeP(p.tok.ident, p) # skip operator: - getTok(p) - optInd(p, a) - # read sub-expression with higher priority: - var b = simpleExprAux(p, opPrec + leftAssoc, modeB) - addSon(a, opNode) - addSon(a, result) - addSon(a, b) - result = a - opPrec = getPrecedence(p.tok) - -proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode = - result = primary(p, mode) - result = parseOperators(p, result, limit, mode) - -proc simpleExpr(p: var TParser, mode = pmNormal): PNode = - result = simpleExprAux(p, -1, mode) - -proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = - #| condExpr = expr colcom expr optInd - #| ('elif' expr colcom expr optInd)* - #| 'else' colcom expr - #| ifExpr = 'if' condExpr - #| whenExpr = 'when' condExpr - result = newNodeP(kind, p) - while true: - getTok(p) # skip `if`, `elif` - var branch = newNodeP(nkElifExpr, p) - addSon(branch, parseExpr(p)) - colcom(p, branch) - addSon(branch, parseExpr(p)) - optInd(p, branch) - addSon(result, branch) - if p.tok.tokType != tkElif: break - var branch = newNodeP(nkElseExpr, p) - eat(p, tkElse) - colcom(p, branch) - addSon(branch, parseExpr(p)) - addSon(result, branch) - -proc parsePragma(p: var TParser): PNode = - result = newNodeP(nkPragma, p) - inc p.inPragma - if isAt(p.tok): - while isAt(p.tok): - getTok(p) - var a = parseExpr(p) - optInd(p, a) - if a.kind in nkCallKinds and a.len == 2: - let repaired = newNodeI(nkExprColonExpr, a.info) - repaired.add a[0] - repaired.add a[1] - a = repaired - addSon(result, a) - skipComment(p, a) - else: - getTok(p) - optInd(p, result) - while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}: - var a = exprColonEqExpr(p) - addSon(result, a) - if p.tok.tokType == tkComma: - getTok(p) - skipComment(p, a) - optPar(p) - if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p) - else: parMessage(p, errTokenExpected, ".}") - dec p.inPragma - -proc identVis(p: var TParser; allowDot=false): PNode = - #| identVis = symbol opr? # postfix position - #| identVisDot = symbol '.' optInd symbol opr? - var a = parseSymbol(p) - if p.tok.tokType == tkOpr: - result = newNodeP(nkPostfix, p) - addSon(result, newIdentNodeP(p.tok.ident, p)) - addSon(result, a) - getTok(p) - elif p.tok.tokType == tkDot and allowDot: - result = dotExpr(p, a) - else: - result = a - -proc identWithPragma(p: var TParser; allowDot=false): PNode = - #| identWithPragma = identVis pragma? - #| identWithPragmaDot = identVisDot pragma? - var a = identVis(p, allowDot) - if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): - result = newNodeP(nkPragmaExpr, p) - addSon(result, a) - addSon(result, parsePragma(p)) - else: - result = a - -type - TDeclaredIdentFlag = enum - withPragma, # identifier may have pragma - withBothOptional # both ':' and '=' parts are optional - TDeclaredIdentFlags = set[TDeclaredIdentFlag] - -proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode = - #| declColonEquals = identWithPragma (comma identWithPragma)* comma? - #| (':' optInd typeDesc)? ('=' optInd expr)? - #| identColonEquals = ident (comma ident)* comma? - #| (':' optInd typeDesc)? ('=' optInd expr)?) - var a: PNode - result = newNodeP(nkIdentDefs, p) - while true: - case p.tok.tokType - of tkSymbol, tkAccent: - if withPragma in flags: a = identWithPragma(p) - else: a = parseSymbol(p) - if a.kind == nkEmpty: return - else: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - if p.tok.tokType == tkColon: - getTok(p) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType != tkEquals and withBothOptional notin flags: - parMessage(p, errColonOrEqualsExpected, p.tok) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - else: - addSon(result, ast.emptyNode) - -proc parseTuple(p: var TParser): PNode = - result = newNodeP(nkTupleTy, p) - getTok(p) - if p.tok.tokType in {tkBracketLe, tkCurlyLe}: - let usedCurly = p.tok.tokType == tkCurlyLe - getTok(p) - optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = parseIdentColonEquals(p, {}) - addSon(result, a) - if p.tok.tokType notin {tkComma, tkSemiColon}: break - getTok(p) - skipComment(p, a) - optPar(p) - if usedCurly: eat(p, tkCurlyRi) - else: eat(p, tkBracketRi) - else: - result = newNodeP(nkTupleClassTy, p) - -proc parseParamList(p: var TParser, retColon = true): PNode = - #| paramList = '(' declColonEquals ^* (comma/semicolon) ')' - #| paramListArrow = paramList? ('->' optInd typeDesc)? - #| paramListColon = paramList? (':' optInd typeDesc)? - var a: PNode - result = newNodeP(nkFormalParams, p) - addSon(result, ast.emptyNode) # return type - let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0 - if hasParLe: - getTok(p) - optInd(p, result) - while true: - case p.tok.tokType - of tkSymbol, tkAccent: - a = parseIdentColonEquals(p, {withBothOptional, withPragma}) - of tkParRi: - break - else: - parMessage(p, errTokenExpected, ")") - break - addSon(result, a) - if p.tok.tokType notin {tkComma, tkSemiColon}: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkParRi) - let hasRet = if retColon: p.tok.tokType == tkColon - else: p.tok.tokType == tkOpr and p.tok.ident.s == "->" - if hasRet and p.tok.indent < 0: - getTok(p) - optInd(p, result) - result.sons[0] = parseTypeDesc(p) - elif not retColon and not hasParle: - # Mark as "not there" in order to mark for deprecation in the semantic pass: - result = ast.emptyNode - -proc optPragmas(p: var TParser): PNode = - if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): - result = parsePragma(p) - else: - result = ast.emptyNode - -proc parseDoBlock(p: var TParser): PNode = - #| doBlock = 'do' paramListArrow pragmas? colcom stmt - let info = parLineInfo(p) - getTok(p) - let params = parseParamList(p, retColon=false) - let pragmas = optPragmas(p) - colcom(p, result) - result = newProcNode(nkDo, info, parseStmt(p), - params = params, - pragmas = pragmas) - -proc parseDoBlocks(p: var TParser, call: PNode) = - #| doBlocks = doBlock ^* IND{=} - while p.tok.tokType == tkDo: - addSon(call, parseDoBlock(p)) - -proc parseCurlyStmt(p: var TParser): PNode = - result = newNodeP(nkStmtList, p) - eat(p, tkCurlyLe) - result.add parseStmt(p) - while p.tok.tokType notin {tkEof, tkCurlyRi}: - if p.tok.tokType == tkSemicolon: getTok(p) - elif p.tok.indent < 0: break - result.add parseStmt(p) - eat(p, tkCurlyRi) - -proc parseProcExpr(p: var TParser, isExpr: bool): PNode = - #| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)? - # either a proc type or a anonymous proc - let info = parLineInfo(p) - getTok(p) - let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0 - let params = parseParamList(p) - let pragmas = optPragmas(p) - if p.tok.tokType == tkCurlyLe and isExpr: - result = newProcNode(nkLambda, info, parseCurlyStmt(p), - params = params, - pragmas = pragmas) - else: - result = newNodeI(nkProcTy, info) - if hasSignature: - addSon(result, params) - addSon(result, pragmas) - -proc isExprStart(p: TParser): bool = - case p.tok.tokType - of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, - tkProc, tkIterator, tkBind, tkAddr, - tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, - tkTuple, tkObject, tkType, tkWhen, tkCase, tkOut: - result = true - else: result = false - -proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) = - while true: - var s = parseSymbol(p, allowNil) - if s.kind == nkEmpty: break - addSon(result, s) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, s) - -proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, - mode: TPrimaryMode): PNode = - #| distinct = 'distinct' optInd typeDesc - result = newNodeP(kind, p) - getTok(p) - optInd(p, result) - if not isOperator(p.tok) and isExprStart(p): - addSon(result, primary(p, mode)) - if kind == nkDistinctTy and p.tok.tokType == tkSymbol: - var nodeKind: TNodeKind - if p.tok.ident.s == "with": - nodeKind = nkWith - elif p.tok.ident.s == "without": - nodeKind = nkWithout - else: - return result - getTok(p) - let list = newNodeP(nodeKind, p) - result.addSon list - parseSymbolList(p, list, allowNil = true) - -proc parseExpr(p: var TParser): PNode = - #| expr = (ifExpr - #| | whenExpr - #| | caseExpr - #| | tryExpr) - #| / simpleExpr - case p.tok.tokType: - of tkIf: result = parseIfExpr(p, nkIfExpr) - of tkWhen: result = parseIfExpr(p, nkWhenExpr) - of tkCase: result = parseCase(p) - of tkTry: result = parseTry(p) - else: result = simpleExpr(p) - -proc parseEnum(p: var TParser): PNode -proc parseObject(p: var TParser): PNode -proc parseTypeClass(p: var TParser): PNode - -proc primary(p: var TParser, mode: TPrimaryMode): PNode = - #| typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple' - #| | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum' - #| primary = typeKeyw typeDescK - #| / prefixOperator* identOrLiteral primarySuffix* - #| / 'static' primary - #| / 'bind' primary - if isOperator(p.tok): - let isSigil = isSigilLike(p.tok) - result = newNodeP(nkPrefix, p) - var a = newIdentNodeP(p.tok.ident, p) - addSon(result, a) - getTok(p) - optInd(p, a) - if isSigil: - #XXX prefix operators - addSon(result, primary(p, pmSkipSuffix)) - result = primarySuffix(p, result) - else: - addSon(result, primary(p, pmNormal)) - return - - case p.tok.tokType: - of tkTuple: result = parseTuple(p) - of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}) - of tkIterator: - result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}) - if result.kind == nkLambda: result.kind = nkIteratorDef - else: result.kind = nkIteratorTy - of tkEnum: - if mode == pmTypeDef: - result = parseEnum(p) - else: - result = newNodeP(nkEnumTy, p) - getTok(p) - of tkObject: - if mode == pmTypeDef: - result = parseObject(p) - else: - result = newNodeP(nkObjectTy, p) - getTok(p) - of tkConcept: - if mode == pmTypeDef: - result = parseTypeClass(p) - else: - parMessage(p, errInvalidToken, p.tok) - of tkStatic: - let info = parLineInfo(p) - getTokNoInd(p) - let next = primary(p, pmNormal) - if next.kind == nkBracket and next.sonsLen == 1: - result = newNode(nkStaticTy, info, @[next.sons[0]]) - else: - result = newNode(nkStaticExpr, info, @[next]) - of tkBind: - result = newNodeP(nkBind, p) - getTok(p) - optInd(p, result) - addSon(result, primary(p, pmNormal)) - of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode) - of tkOut: result = parseTypeDescKAux(p, nkVarTy, mode) - of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode) - of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode) - of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode) - else: - result = identOrLiteral(p, mode) - if mode != pmSkipSuffix: - result = primarySuffix(p, result) - -proc parseTypeDesc(p: var TParser): PNode = - #| typeDesc = simpleExpr - result = simpleExpr(p, pmTypeDesc) - -proc parseTypeDefAux(p: var TParser): PNode = - #| typeDefAux = simpleExpr - #| | 'concept' typeClass - result = simpleExpr(p, pmTypeDef) - -proc makeCall(n: PNode): PNode = - ## Creates a call if the given node isn't already a call. - if n.kind in nkCallKinds: - result = n - else: - result = newNodeI(nkCall, n.info) - result.add n - -proc parseMacroColon(p: var TParser, x: PNode): PNode = - #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt - #| | IND{=} 'elif' expr ':' stmt - #| | IND{=} 'except' exprList ':' stmt - #| | IND{=} 'else' ':' stmt )* - result = x - if p.tok.tokType == tkColon and p.tok.indent < 0: - result = makeCall(result) - getTok(p) - skipComment(p, result) - let stmtList = newNodeP(nkStmtList, p) - if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}: - let body = parseStmt(p) - stmtList.add body - #addSon(result, makeStmtList(body)) - while true: - var b: PNode - case p.tok.tokType - of tkOf: - b = newNodeP(nkOfBranch, p) - exprList(p, tkCurlyLe, b) - of tkElif: - b = newNodeP(nkElifBranch, p) - getTok(p) - optInd(p, b) - addSon(b, parseExpr(p)) - of tkExcept: - b = newNodeP(nkExceptBranch, p) - exprList(p, tkCurlyLe, b) - of tkElse: - b = newNodeP(nkElse, p) - getTok(p) - else: break - addSon(b, parseCurlyStmt(p)) - addSon(stmtList, b) - if b.kind == nkElse: break - if stmtList.len == 1 and stmtList[0].kind == nkStmtList: - # to keep backwards compatibility (see tests/vm/tstringnil) - result.add stmtList[0] - else: - result.add stmtList - -proc parseExprStmt(p: var TParser): PNode = - #| exprStmt = simpleExpr - #| (( '=' optInd expr ) - #| / ( expr ^+ comma - #| doBlocks - #| / macroColon - #| ))? - var a = simpleExpr(p) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - var b = parseExpr(p) - result = newNodeI(nkAsgn, a.info) - addSon(result, a) - addSon(result, b) - else: - # simpleExpr parsed 'p a' from 'p a, b'? - if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand: - result = a - while true: - getTok(p) - optInd(p, result) - var e = parseExpr(p) - addSon(result, e) - if p.tok.tokType != tkComma: break - elif p.tok.indent < 0 and isExprStart(p): - if a.kind == nkCommand: - result = a - else: - result = newNode(nkCommand, a.info, @[a]) - while true: - var e = parseExpr(p) - addSon(result, e) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, result) - else: - result = a - if p.tok.tokType == tkDo and p.tok.indent < 0: - result = makeCall(result) - parseDoBlocks(p, result) - return result - result = parseMacroColon(p, result) - -proc parseModuleName(p: var TParser, kind: TNodeKind): PNode = - result = parseExpr(p) - -proc parseImport(p: var TParser, kind: TNodeKind): PNode = - #| importStmt = 'import' optInd expr - #| ((comma expr)* - #| / 'except' optInd (expr ^+ comma)) - result = newNodeP(kind, p) - getTok(p) # skip `import` or `export` - optInd(p, result) - var a = parseModuleName(p, kind) - addSon(result, a) - if p.tok.tokType in {tkComma, tkExcept}: - if p.tok.tokType == tkExcept: - result.kind = succ(kind) - getTok(p) - optInd(p, result) - while true: - # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}: - a = parseModuleName(p, kind) - if a.kind == nkEmpty: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - #expectNl(p) - -proc parseIncludeStmt(p: var TParser): PNode = - #| includeStmt = 'include' optInd expr ^+ comma - result = newNodeP(nkIncludeStmt, p) - getTok(p) # skip `import` or `include` - optInd(p, result) - while true: - # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}: - var a = parseExpr(p) - if a.kind == nkEmpty: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - #expectNl(p) - -proc parseFromStmt(p: var TParser): PNode = - #| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)* - result = newNodeP(nkFromStmt, p) - getTok(p) # skip `from` - optInd(p, result) - var a = parseModuleName(p, nkImportStmt) - addSon(result, a) #optInd(p, a); - eat(p, tkImport) - optInd(p, result) - while true: - # p.tok.tokType notin {tkEof, tkSad, tkDed}: - a = parseExpr(p) - if a.kind == nkEmpty: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - #expectNl(p) - -proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode = - #| returnStmt = 'return' optInd expr? - #| raiseStmt = 'raise' optInd expr? - #| yieldStmt = 'yield' optInd expr? - #| discardStmt = 'discard' optInd expr? - #| breakStmt = 'break' optInd expr? - #| continueStmt = 'break' optInd expr? - result = newNodeP(kind, p) - getTok(p) - if p.tok.tokType == tkComment: - skipComment(p, result) - addSon(result, ast.emptyNode) - elif p.tok.indent >= 0 or not isExprStart(p): - # NL terminates: - addSon(result, ast.emptyNode) - else: - addSon(result, parseExpr(p)) - -proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode = - #| condStmt = expr colcom stmt COMMENT? - #| (IND{=} 'elif' expr colcom stmt)* - #| (IND{=} 'else' colcom stmt)? - #| ifStmt = 'if' condStmt - #| whenStmt = 'when' condStmt - result = newNodeP(kind, p) - while true: - getTok(p) # skip `if`, `when`, `elif` - var branch = newNodeP(nkElifBranch, p) - optInd(p, branch) - addSon(branch, parseExpr(p)) - colcom(p, branch) - addSon(branch, parseCurlyStmt(p)) - skipComment(p, branch) - addSon(result, branch) - if p.tok.tokType != tkElif: break - if p.tok.tokType == tkElse: - var branch = newNodeP(nkElse, p) - eat(p, tkElse) - addSon(branch, parseCurlyStmt(p)) - addSon(result, branch) - -proc parseWhile(p: var TParser): PNode = - #| whileStmt = 'while' expr colcom stmt - result = newNodeP(nkWhileStmt, p) - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseCase(p: var TParser): PNode = - #| ofBranch = 'of' exprList colcom stmt - #| ofBranches = ofBranch (IND{=} ofBranch)* - #| (IND{=} 'elif' expr colcom stmt)* - #| (IND{=} 'else' colcom stmt)? - #| caseStmt = 'case' expr ':'? COMMENT? - #| (IND{>} ofBranches DED - #| | IND{=} ofBranches) - var - b: PNode - inElif= false - result = newNodeP(nkCaseStmt, p) - getTok(p) - addSon(result, parseExpr(p)) - eat(p, tkCurlyLe) - skipComment(p, result) - - while true: - case p.tok.tokType - of tkOf: - if inElif: break - b = newNodeP(nkOfBranch, p) - exprList(p, tkCurlyLe, b) - of tkElif: - inElif = true - b = newNodeP(nkElifBranch, p) - getTok(p) - optInd(p, b) - addSon(b, parseExpr(p)) - of tkElse: - b = newNodeP(nkElse, p) - getTok(p) - else: break - skipComment(p, b) - addSon(b, parseCurlyStmt(p)) - addSon(result, b) - if b.kind == nkElse: break - eat(p, tkCurlyRi) - -proc parseTry(p: var TParser): PNode = - #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally') - #| (IND{=}? 'except' exprList colcom stmt)* - #| (IND{=}? 'finally' colcom stmt)? - #| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally') - #| (optInd 'except' exprList colcom stmt)* - #| (optInd 'finally' colcom stmt)? - result = newNodeP(nkTryStmt, p) - getTok(p) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - var b: PNode = nil - while true: - case p.tok.tokType - of tkExcept: - b = newNodeP(nkExceptBranch, p) - exprList(p, tkCurlyLe, b) - of tkFinally: - b = newNodeP(nkFinally, p) - getTok(p) - else: break - skipComment(p, b) - addSon(b, parseCurlyStmt(p)) - addSon(result, b) - if b.kind == nkFinally: break - if b == nil: parMessage(p, errTokenExpected, "except") - -proc parseFor(p: var TParser): PNode = - #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt - result = newNodeP(nkForStmt, p) - getTokNoInd(p) - var a = identWithPragma(p) - addSon(result, a) - while p.tok.tokType == tkComma: - getTok(p) - optInd(p, a) - a = identWithPragma(p) - addSon(result, a) - eat(p, tkIn) - addSon(result, parseExpr(p)) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseBlock(p: var TParser): PNode = - #| blockStmt = 'block' symbol? colcom stmt - result = newNodeP(nkBlockStmt, p) - getTokNoInd(p) - if p.tok.tokType == tkCurlyLe: addSon(result, ast.emptyNode) - else: addSon(result, parseSymbol(p)) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode = - #| staticStmt = 'static' colcom stmt - #| deferStmt = 'defer' colcom stmt - result = newNodeP(k, p) - getTok(p) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseAsm(p: var TParser): PNode = - #| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT) - result = newNodeP(nkAsmStmt, p) - getTokNoInd(p) - if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): addSon(result, parsePragma(p)) - else: addSon(result, ast.emptyNode) - case p.tok.tokType - of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p)) - of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)) - of tkTripleStrLit: addSon(result, - newStrNodeP(nkTripleStrLit, p.tok.literal, p)) - else: - parMessage(p, errStringLiteralExpected) - addSon(result, ast.emptyNode) - return - getTok(p) - -proc parseGenericParam(p: var TParser): PNode = - #| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)? - var a: PNode - result = newNodeP(nkIdentDefs, p) - while true: - case p.tok.tokType - of tkIn, tkOut: - let t = p.tok.tokType - getTok(p) - expectIdent(p) - a = parseSymbol(p) - of tkSymbol, tkAccent: - a = parseSymbol(p) - if a.kind == nkEmpty: return - else: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - if p.tok.tokType == tkColon: - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - else: - addSon(result, ast.emptyNode) - -proc parseGenericParamList(p: var TParser): PNode = - #| genericParamList = '[' optInd - #| genericParam ^* (comma/semicolon) optPar ']' - result = newNodeP(nkGenericParams, p) - getTok(p) - optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = parseGenericParam(p) - addSon(result, a) - if p.tok.tokType notin {tkComma, tkSemiColon}: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkBracketRi) - -proc parsePattern(p: var TParser): PNode = - eat(p, tkBracketDotLe) - result = parseStmt(p) - eat(p, tkBracketDotRi) - -proc validInd(p: TParser): bool = p.tok.indent < 0 - -proc parseRoutine(p: var TParser, kind: TNodeKind): PNode = - #| indAndComment = (IND{>} COMMENT)? | COMMENT? - #| routine = optInd identVis pattern? genericParamList? - #| paramListColon pragma? ('=' COMMENT? stmt)? indAndComment - result = newNodeP(kind, p) - getTok(p) - optInd(p, result) - addSon(result, identVis(p)) - if p.tok.tokType == tkBracketDotLe and p.validInd: - addSon(result, p.parsePattern) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkBracketLe and p.validInd: - result.add(p.parseGenericParamList) - else: - addSon(result, ast.emptyNode) - addSon(result, p.parseParamList) - if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd: - addSon(result, p.parsePragma) - else: - addSon(result, ast.emptyNode) - # empty exception tracking: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkCurlyLe: - addSon(result, parseCurlyStmt(p)) - else: - addSon(result, ast.emptyNode) - indAndComment(p, result) - -proc newCommentStmt(p: var TParser): PNode = - #| commentStmt = COMMENT - result = newNodeP(nkCommentStmt, p) - result.comment = p.tok.literal - getTok(p) - -type - TDefParser = proc (p: var TParser): PNode {.nimcall.} - -proc parseSection(p: var TParser, kind: TNodeKind, - defparser: TDefParser): PNode = - #| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED) - result = newNodeP(kind, p) - if kind != nkTypeSection: getTok(p) - skipComment(p, result) - if p.tok.tokType == tkParLe: - getTok(p) - skipComment(p, result) - while true: - case p.tok.tokType - of tkSymbol, tkAccent, tkParLe: - var a = defparser(p) - skipComment(p, a) - addSon(result, a) - of tkComment: - var a = newCommentStmt(p) - addSon(result, a) - of tkParRi: break - else: - parMessage(p, errIdentifierExpected, p.tok) - break - eat(p, tkParRi) - if result.len == 0: parMessage(p, errIdentifierExpected, p.tok) - elif p.tok.tokType in {tkSymbol, tkAccent, tkBracketLe}: - # tkBracketLe is allowed for ``var [x, y] = ...`` tuple parsing - addSon(result, defparser(p)) - else: - parMessage(p, errIdentifierExpected, p.tok) - -proc parseConstant(p: var TParser): PNode = - #| constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment - result = newNodeP(nkConstDef, p) - addSon(result, identWithPragma(p)) - if p.tok.tokType == tkColon: - getTok(p) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - else: - addSon(result, ast.emptyNode) - eat(p, tkEquals) - optInd(p, result) - addSon(result, parseExpr(p)) - indAndComment(p, result) - -proc parseEnum(p: var TParser): PNode = - #| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+ - result = newNodeP(nkEnumTy, p) - getTok(p) - addSon(result, ast.emptyNode) - optInd(p, result) - flexComment(p, result) - eat(p, tkCurlyLe) - optInd(p, result) - while p.tok.tokType notin {tkEof, tkCurlyRi}: - var a = parseSymbol(p) - if a.kind == nkEmpty: return - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, a) - var b = a - a = newNodeP(nkEnumFieldDef, p) - addSon(a, b) - addSon(a, parseExpr(p)) - if p.tok.indent < 0: - rawSkipComment(p, a) - if p.tok.tokType == tkComma: - getTok(p) - rawSkipComment(p, a) - addSon(result, a) - eat(p, tkCurlyRi) - if result.len <= 1: - lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok)) - -proc parseObjectPart(p: var TParser; needsCurly: bool): PNode -proc parseObjectWhen(p: var TParser): PNode = - result = newNodeP(nkRecWhen, p) - while true: - getTok(p) # skip `when`, `elif` - var branch = newNodeP(nkElifBranch, p) - optInd(p, branch) - addSon(branch, parseExpr(p)) - colcom(p, branch) - addSon(branch, parseObjectPart(p, true)) - flexComment(p, branch) - addSon(result, branch) - if p.tok.tokType != tkElif: break - if p.tok.tokType == tkElse: - var branch = newNodeP(nkElse, p) - eat(p, tkElse) - colcom(p, branch) - addSon(branch, parseObjectPart(p, true)) - flexComment(p, branch) - addSon(result, branch) - -proc parseObjectCase(p: var TParser): PNode = - result = newNodeP(nkRecCase, p) - getTokNoInd(p) - var a = newNodeP(nkIdentDefs, p) - addSon(a, identWithPragma(p)) - eat(p, tkColon) - addSon(a, parseTypeDesc(p)) - addSon(a, ast.emptyNode) - addSon(result, a) - eat(p, tkCurlyLe) - flexComment(p, result) - while true: - var b: PNode - case p.tok.tokType - of tkOf: - b = newNodeP(nkOfBranch, p) - exprList(p, tkColon, b) - of tkElse: - b = newNodeP(nkElse, p) - getTok(p) - else: break - colcom(p, b) - var fields = parseObjectPart(p, true) - if fields.kind == nkEmpty: - parMessage(p, errIdentifierExpected, p.tok) - fields = newNodeP(nkNilLit, p) # don't break further semantic checking - addSon(b, fields) - addSon(result, b) - if b.kind == nkElse: break - eat(p, tkCurlyRi) - -proc parseObjectPart(p: var TParser; needsCurly: bool): PNode = - if p.tok.tokType == tkCurlyLe: - result = newNodeP(nkRecList, p) - getTok(p) - rawSkipComment(p, result) - while true: - case p.tok.tokType - of tkCase, tkWhen, tkSymbol, tkAccent, tkNil, tkDiscard: - addSon(result, parseObjectPart(p, false)) - of tkCurlyRi: break - else: - parMessage(p, errIdentifierExpected, p.tok) - break - eat(p, tkCurlyRi) - else: - if needsCurly: - parMessage(p, errTokenExpected, "{") - case p.tok.tokType - of tkWhen: - result = parseObjectWhen(p) - of tkCase: - result = parseObjectCase(p) - of tkSymbol, tkAccent: - result = parseIdentColonEquals(p, {withPragma}) - if p.tok.indent < 0: rawSkipComment(p, result) - of tkNil, tkDiscard: - result = newNodeP(nkNilLit, p) - getTok(p) - else: - result = ast.emptyNode - -proc parseObject(p: var TParser): PNode = - result = newNodeP(nkObjectTy, p) - getTok(p) - if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd: - addSon(result, parsePragma(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkOf and p.tok.indent < 0: - var a = newNodeP(nkOfInherit, p) - getTok(p) - addSon(a, parseTypeDesc(p)) - addSon(result, a) - else: - addSon(result, ast.emptyNode) - skipComment(p, result) - # an initial IND{>} HAS to follow: - addSon(result, parseObjectPart(p, true)) - -proc parseTypeClassParam(p: var TParser): PNode = - if p.tok.tokType in {tkOut, tkVar}: - result = newNodeP(nkVarTy, p) - getTok(p) - result.addSon(p.parseSymbol) - else: - result = p.parseSymbol - -proc parseTypeClass(p: var TParser): PNode = - #| typeClassParam = ('var' | 'out')? symbol - #| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? - #| &IND{>} stmt - result = newNodeP(nkTypeClassTy, p) - getTok(p) - var args = newNodeP(nkArgList, p) - addSon(result, args) - addSon(args, p.parseTypeClassParam) - while p.tok.tokType == tkComma: - getTok(p) - addSon(args, p.parseTypeClassParam) - if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd: - addSon(result, parsePragma(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkOf and p.tok.indent < 0: - var a = newNodeP(nkOfInherit, p) - getTok(p) - while true: - addSon(a, parseTypeDesc(p)) - if p.tok.tokType != tkComma: break - getTok(p) - addSon(result, a) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkComment: - skipComment(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseTypeDef(p: var TParser): PNode = - #| - #| typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux - #| indAndComment? - result = newNodeP(nkTypeDef, p) - addSon(result, identWithPragma(p, allowDot=true)) - if p.tok.tokType == tkBracketLe and p.validInd: - addSon(result, parseGenericParamList(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - addSon(result, parseTypeDefAux(p)) - else: - addSon(result, ast.emptyNode) - indAndComment(p, result) # special extension! - -proc parseVarTuple(p: var TParser): PNode = - #| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr - result = newNodeP(nkVarTuple, p) - getTok(p) # skip '(' - optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = identWithPragma(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - addSon(result, ast.emptyNode) # no type desc - optPar(p) - eat(p, tkBracketRi) - eat(p, tkEquals) - optInd(p, result) - addSon(result, parseExpr(p)) - -proc parseVariable(p: var TParser): PNode = - #| variable = (varTuple / identColonEquals) indAndComment - if p.tok.tokType == tkBracketLe: result = parseVarTuple(p) - else: result = parseIdentColonEquals(p, {withPragma}) - indAndComment(p, result) - -proc parseBind(p: var TParser, k: TNodeKind): PNode = - #| bindStmt = 'bind' optInd qualifiedIdent ^+ comma - #| mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma - result = newNodeP(k, p) - getTok(p) - optInd(p, result) - while true: - var a = qualifiedIdent(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - -proc parseStmtPragma(p: var TParser): PNode = - result = parsePragma(p) - if p.tok.tokType == tkCurlyLe: - let a = result - result = newNodeI(nkPragmaBlock, a.info) - getTok(p) - skipComment(p, result) - result.add a - result.add parseStmt(p) - eat(p, tkCurlyRi) - -proc simpleStmt(p: var TParser): PNode = - case p.tok.tokType - of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt) - of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt) - of tkYield: result = parseReturnOrRaise(p, nkYieldStmt) - of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt) - of tkBreak: result = parseReturnOrRaise(p, nkBreakStmt) - of tkContinue: result = parseReturnOrRaise(p, nkContinueStmt) - of tkCurlyDotLe: result = parseStmtPragma(p) - of tkImport: result = parseImport(p, nkImportStmt) - of tkExport: result = parseImport(p, nkExportStmt) - of tkFrom: result = parseFromStmt(p) - of tkInclude: result = parseIncludeStmt(p) - of tkComment: result = newCommentStmt(p) - else: - if isExprStart(p): result = parseExprStmt(p) - else: result = ast.emptyNode - if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result) - -proc complexOrSimpleStmt(p: var TParser): PNode = - case p.tok.tokType - of tkIf: result = parseIfOrWhen(p, nkIfStmt) - of tkWhile: result = parseWhile(p) - of tkCase: result = parseCase(p) - of tkTry: result = parseTry(p) - of tkFor: result = parseFor(p) - of tkBlock: result = parseBlock(p) - of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt) - of tkDefer: result = parseStaticOrDefer(p, nkDefer) - of tkAsm: result = parseAsm(p) - of tkProc: result = parseRoutine(p, nkProcDef) - of tkMethod: result = parseRoutine(p, nkMethodDef) - of tkIterator: result = parseRoutine(p, nkIteratorDef) - of tkMacro: result = parseRoutine(p, nkMacroDef) - of tkTemplate: result = parseRoutine(p, nkTemplateDef) - of tkConverter: result = parseRoutine(p, nkConverterDef) - of tkType: - getTok(p) - if p.tok.tokType == tkBracketLe: - getTok(p) - result = newNodeP(nkTypeOfExpr, p) - result.addSon(primary(p, pmTypeDesc)) - eat(p, tkBracketRi) - result = parseOperators(p, result, -1, pmNormal) - else: - result = parseSection(p, nkTypeSection, parseTypeDef) - of tkConst: result = parseSection(p, nkConstSection, parseConstant) - of tkLet: result = parseSection(p, nkLetSection, parseVariable) - of tkWhen: result = parseIfOrWhen(p, nkWhenStmt) - of tkVar: result = parseSection(p, nkVarSection, parseVariable) - of tkBind: result = parseBind(p, nkBindStmt) - of tkMixin: result = parseBind(p, nkMixinStmt) - of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable) - else: result = simpleStmt(p) - -proc parseStmt(p: var TParser): PNode = - result = complexOrSimpleStmt(p) - -proc parseAll*(p: var TParser): PNode = - ## Parses the rest of the input stream held by the parser into a PNode. - result = newNodeP(nkStmtList, p) - while p.tok.tokType != tkEof: - var a = complexOrSimpleStmt(p) - if a.kind != nkEmpty: - addSon(result, a) - else: - parMessage(p, errExprExpected, p.tok) - # bugfix: consume a token here to prevent an endless loop: - getTok(p) - -proc parseTopLevelStmt*(p: var TParser): PNode = - ## Implements an iterator which, when called repeatedly, returns the next - ## top-level statement or emptyNode if end of stream. - result = ast.emptyNode - while true: - case p.tok.tokType - of tkSemiColon: getTok(p) - of tkEof: break - else: - result = complexOrSimpleStmt(p) - if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok) - break diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 56d8d58864..2542a08ea4 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -137,7 +137,7 @@ proc hasIncludes(n:PNode): bool = proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = - result = syntaxes.parseFile(fileIdx, cache) + result = syntaxes.parseFile(fileIdx, cache, graph.config) graph.addDep(s, fileIdx) graph.addIncludeDep(FileIndex s.position, fileIdx) @@ -273,9 +273,9 @@ proc hasCommand(n: PNode): bool = of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt, nkLetSection, nkConstSection, nkVarSection, nkIdentDefs: - for a in n: - if a.hasCommand: - return true + for a in n: + if a.hasCommand: + return true else: return false diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index c533f4cb44..6ef42f15ec 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -28,7 +28,7 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) = proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; config: ConfigRef): PEvalContext = # For Nimble we need to export 'setupVM'. - result = newCtx(module, cache) + result = newCtx(module, cache, config) result.mode = emRepl registerAdditionalOps(result) diff --git a/compiler/sem.nim b/compiler/sem.nim index 52282d0e49..d8e5b7f205 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -313,7 +313,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = msgs.gErrorMax = high(int) try: - result = evalConstExpr(c.module, c.cache, e) + result = evalConstExpr(c.module, c.cache, c.graph.config, e) if result == nil or result.kind == nkEmpty: result = nil else: @@ -334,7 +334,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode = result = getConstExpr(c.module, e) if result == nil: #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) - result = evalConstExpr(c.module, c.cache, e) + result = evalConstExpr(c.module, c.cache, c.graph.config, e) if result == nil or result.kind == nkEmpty: if e.info != n.info: pushInfoContext(n.info) @@ -439,7 +439,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, #if c.evalContext == nil: # c.evalContext = c.createEvalContext(emStatic) - result = evalMacroCall(c.module, c.cache, n, nOrig, sym) + result = evalMacroCall(c.module, c.cache, c.graph.config, n, nOrig, sym) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, sym, flags) result = wrapInComesFrom(nOrig.info, sym, result) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index feca087fce..4a3672aa0d 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -605,12 +605,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = call.add(a) #echo "NOW evaluating at compile time: ", call.renderTree if sfCompileTime in callee.flags: - result = evalStaticExpr(c.module, c.cache, call, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph.config, call, c.p.owner) if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(call)) else: result = fixupTypeAfterEval(c, result, n) else: - result = evalConstExpr(c.module, c.cache, call) + result = evalConstExpr(c.module, c.cache, c.graph.config, call) if result.isNil: result = n else: result = fixupTypeAfterEval(c, result, n) #if result != n: @@ -619,7 +619,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = proc semStaticExpr(c: PContext, n: PNode): PNode = let a = semExpr(c, n.sons[0]) if a.findUnresolvedStatic != nil: return a - result = evalStaticExpr(c.module, c.cache, a, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph.config, a, c.p.owner) if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(n)) result = emptyNode diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f5fdc3445f..b0bd4e0f61 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -545,7 +545,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = b.sons[j] = newSymNode(v) checkNilable(v) if sfCompileTime in v.flags: hasCompileTime = true - if hasCompileTime: vm.setupCompileTimeVar(c.module, c.cache, result) + if hasCompileTime: + vm.setupCompileTimeVar(c.module, c.cache, c.graph.config, result) proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) @@ -1755,7 +1756,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode = #writeStackTrace() let a = semStmt(c, n.sons[0]) n.sons[0] = a - evalStaticStmt(c.module, c.cache, a, c.p.owner) + evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner) result = newNodeI(nkDiscardStmt, n.info, 1) result.sons[0] = emptyNode diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 5413565e6f..974df50fb2 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -11,17 +11,17 @@ import strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser, - pbraces, filters, filter_tmpl, renderer + filters, filter_tmpl, renderer type TFilterKind* = enum filtNone, filtTemplate, filtReplace, filtStrip TParserKind* = enum - skinStandard, skinStrongSpaces, skinBraces, skinEndX + skinStandard, skinStrongSpaces, skinEndX const parserNames*: array[TParserKind, string] = ["standard", "strongspaces", - "braces", "endx"] + "endx"] filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace", "strip"] @@ -34,8 +34,6 @@ proc parseAll*(p: var TParsers): PNode = case p.skin of skinStandard, skinStrongSpaces: result = parser.parseAll(p.parser) - of skinBraces: - result = pbraces.parseAll(p.parser) of skinEndX: internalError("parser to implement") result = ast.emptyNode @@ -44,8 +42,6 @@ proc parseTopLevelStmt*(p: var TParsers): PNode = case p.skin of skinStandard, skinStrongSpaces: result = parser.parseTopLevelStmt(p.parser) - of skinBraces: - result = pbraces.parseTopLevelStmt(p.parser) of skinEndX: internalError("parser to implement") result = ast.emptyNode @@ -62,7 +58,8 @@ proc containsShebang(s: string, i: int): bool = while j < s.len and s[j] in Whitespace: inc(j) result = s[j] == '/' -proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNode = +proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache; + config: ConfigRef): PNode = result = ast.emptyNode var s = llStreamOpen(filename, fmRead) if s != nil: @@ -78,7 +75,7 @@ proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNo inc(i, 2) while i < line.len and line[i] in Whitespace: inc(i) var q: TParser - parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache) + parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache, config) result = parser.parseAll(q) parser.closeParser(q) llStreamClose(s) @@ -139,23 +136,23 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string, result = applyFilter(p, n, filename, result) proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream; - cache: IdentCache) = + cache: IdentCache; config: ConfigRef) = var s: PLLStream p.skin = skinStandard let filename = fileIdx.toFullPathConsiderDirty - var pipe = parsePipe(filename, inputstream, cache) + var pipe = parsePipe(filename, inputstream, cache, config) if pipe != nil: s = evalPipe(p, pipe, filename, inputstream) else: s = inputstream case p.skin - of skinStandard, skinBraces, skinEndX: - parser.openParser(p.parser, fileIdx, s, cache, false) + of skinStandard, skinEndX: + parser.openParser(p.parser, fileIdx, s, cache, config, false) of skinStrongSpaces: - parser.openParser(p.parser, fileIdx, s, cache, true) + parser.openParser(p.parser, fileIdx, s, cache, config, true) proc closeParsers*(p: var TParsers) = parser.closeParser(p.parser) -proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = +proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} = var p: TParsers f: File @@ -163,6 +160,6 @@ proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = if not open(f, filename): rawMessage(errCannotOpenFile, filename) return - openParsers(p, fileIdx, llStreamOpen(f), cache) + openParsers(p, fileIdx, llStreamOpen(f), cache, config) result = parseAll(p) closeParsers(p) diff --git a/compiler/vm.nim b/compiler/vm.nim index 32db8f3785..6c36a14580 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1341,8 +1341,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeB(rkNode) # c.debug[pc].line.int - countLines(regs[rb].strVal) ? var error: string - let ast = parseString(regs[rb].node.strVal, c.cache, c.debug[pc].toFullPath, - c.debug[pc].line.int, + let ast = parseString(regs[rb].node.strVal, c.cache, c.config, + c.debug[pc].toFullPath, c.debug[pc].line.int, proc (info: TLineInfo; msg: TMsgKind; arg: string) = if error.isNil and msg <= msgs.errMax: error = formatMsg(info, msg, arg)) @@ -1355,8 +1355,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcParseStmtToAst: decodeB(rkNode) var error: string - let ast = parseString(regs[rb].node.strVal, c.cache, c.debug[pc].toFullPath, - c.debug[pc].line.int, + let ast = parseString(regs[rb].node.strVal, c.cache, c.config, + c.debug[pc].toFullPath, c.debug[pc].line.int, proc (info: TLineInfo; msg: TMsgKind; arg: string) = if error.isNil and msg <= msgs.errMax: error = formatMsg(info, msg, arg)) @@ -1643,9 +1643,9 @@ include vmops var globalCtx*: PCtx -proc setupGlobalCtx(module: PSym; cache: IdentCache) = +proc setupGlobalCtx(module: PSym; cache: IdentCache; config: ConfigRef) = if globalCtx.isNil: - globalCtx = newCtx(module, cache) + globalCtx = newCtx(module, cache, config) registerAdditionalOps(globalCtx) else: refresh(globalCtx, module) @@ -1656,7 +1656,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = #pushStackFrame(c, newStackFrame()) # XXX produce a new 'globals' environment here: - setupGlobalCtx(module, cache) + setupGlobalCtx(module, cache, graph.config) result = globalCtx when hasFFI: globalCtx.features = {allowFFI, allowCast} @@ -1677,10 +1677,11 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = const evalPass* = makePass(myOpen, nil, myProcess, myClose) -proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode, +proc evalConstExprAux(module: PSym; cache: IdentCache; + config: ConfigRef; prc: PSym, n: PNode, mode: TEvalMode): PNode = let n = transformExpr(module, n) - setupGlobalCtx(module, cache) + setupGlobalCtx(module, cache, config) var c = globalCtx let oldMode = c.mode defer: c.mode = oldMode @@ -1695,17 +1696,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode, result = rawExecute(c, start, tos).regToNode if result.info.col < 0: result.info = n.info -proc evalConstExpr*(module: PSym; cache: IdentCache, e: PNode): PNode = - result = evalConstExprAux(module, cache, nil, e, emConst) +proc evalConstExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode): PNode = + result = evalConstExprAux(module, cache, config, nil, e, emConst) -proc evalStaticExpr*(module: PSym; cache: IdentCache, e: PNode, prc: PSym): PNode = - result = evalConstExprAux(module, cache, prc, e, emStaticExpr) +proc evalStaticExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym): PNode = + result = evalConstExprAux(module, cache, config, prc, e, emStaticExpr) -proc evalStaticStmt*(module: PSym; cache: IdentCache, e: PNode, prc: PSym) = - discard evalConstExprAux(module, cache, prc, e, emStaticStmt) +proc evalStaticStmt*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym) = + discard evalConstExprAux(module, cache, config, prc, e, emStaticStmt) -proc setupCompileTimeVar*(module: PSym; cache: IdentCache, n: PNode) = - discard evalConstExprAux(module, cache, nil, n, emStaticStmt) +proc setupCompileTimeVar*(module: PSym; cache: IdentCache, config: ConfigRef; n: PNode) = + discard evalConstExprAux(module, cache, config, nil, n, emStaticStmt) proc setupMacroParam(x: PNode, typ: PType): TFullReg = case typ.kind @@ -1733,8 +1734,8 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) = const evalMacroLimit = 1000 var evalMacroCounter: int -proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, - sym: PSym): PNode = +proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef; + n, nOrig: PNode, sym: PSym): PNode = # XXX globalError() is ugly here, but I don't know a better solution for now inc(evalMacroCounter) if evalMacroCounter > evalMacroLimit: @@ -1746,7 +1747,7 @@ proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [ n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) - setupGlobalCtx(module, cache) + setupGlobalCtx(module, cache, config) var c = globalCtx c.comesFromHeuristic.line = 0'u16 diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 66bc8dfd27..b0a559d2c2 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -10,7 +10,7 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import ast, passes, msgs, idents, intsets +import ast, passes, msgs, idents, intsets, options const byteExcess* = 128 # we use excess-K for immediates @@ -206,17 +206,19 @@ type callbacks*: seq[tuple[key: string, value: VmCallback]] errorFlag*: string cache*: IdentCache + config*: ConfigRef TPosition* = distinct int PEvalContext* = PCtx -proc newCtx*(module: PSym; cache: IdentCache): PCtx = +proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx = + let conf = if config != nil: config else: newConfigRef() PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "", - cache: cache) + cache: cache, config: conf) proc refresh*(c: PCtx, module: PSym) = c.module = module From dfc17e5f8e0652ebc4c693e5a5900a122b85ab95 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 21:08:45 +0200 Subject: [PATCH 140/214] make Nimble not crash after the refactoring --- compiler/lexer.nim | 3 ++- koch.nim | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 0aeb44ca3a..a655873903 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -237,7 +237,8 @@ proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream; openLexer(lex, filename.fileInfoIdx, inputstream, cache, config) proc closeLexer*(lex: var TLexer) = - inc(lex.config.linesCompiled, lex.lineNumber) + if lex.config != nil: + inc(lex.config.linesCompiled, lex.lineNumber) closeBaseLexer(lex) proc getLineInfo(L: TLexer): TLineInfo = diff --git a/koch.nim b/koch.nim index d51b902ee8..7a75ebf714 100644 --- a/koch.nim +++ b/koch.nim @@ -252,7 +252,7 @@ proc xz(args: string) = proc buildTool(toolname, args: string) = nimexec("cc $# $#" % [args, toolname]) - copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe) + copyFile(dest="bin" / splitFile(toolname).name.exe, source=toolname.exe) proc buildTools(latest: bool) = let nimsugExe = "bin/nimsuggest".exe From bbb0fd4eb734ed1a0445865077c27b05b46d0cbd Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 4 May 2018 14:03:16 +0200 Subject: [PATCH 141/214] remove deprecated stuff from the stdlib; introduce better deprecation warnings --- lib/deprecated/pure/ftpclient.nim | 2 +- lib/packages/docutils/rst.nim | 4 --- lib/packages/docutils/rstast.nim | 3 --- lib/pure/algorithm.nim | 3 --- lib/pure/asyncfutures.nim | 2 -- lib/pure/asynchttpserver.nim | 3 --- lib/pure/asyncnet.nim | 2 -- lib/pure/cgi.nim | 2 -- lib/pure/colors.nim | 2 -- lib/pure/complex.nim | 2 -- lib/pure/db_common.nim | 3 --- lib/pure/dynlib.nim | 6 ++--- lib/pure/encodings.nim | 2 -- lib/pure/events.nim | 3 --- lib/pure/hashes.nim | 1 - lib/pure/htmlparser.nim | 1 - lib/pure/httpclient.nim | 16 ++++------- lib/pure/httpcore.nim | 4 --- lib/pure/httpserver.nim | 2 -- lib/pure/includes/asynccommon.nim | 4 +-- lib/pure/includes/oserr.nim | 44 ------------------------------- lib/pure/json.nim | 15 +++-------- lib/pure/lexbase.nim | 2 -- lib/pure/logging.nim | 4 --- lib/pure/marshal.nim | 1 - lib/pure/memfiles.nim | 2 -- lib/pure/mersenne.nim | 2 -- lib/pure/mimetypes.nim | 2 -- lib/pure/nativesockets.nim | 5 +--- lib/pure/net.nim | 9 ------- lib/pure/nimprof.nim | 2 -- lib/pure/oids.nim | 6 ++--- lib/pure/os.nim | 16 ----------- lib/pure/ospaths.nim | 5 ---- lib/pure/osproc.nim | 33 ++++++++++------------- lib/pure/parsecfg.nim | 3 --- lib/pure/parsecsv.nim | 2 -- lib/pure/parseopt.nim | 2 -- lib/pure/parseopt2.nim | 4 --- lib/pure/parsesql.nim | 2 -- lib/pure/parseutils.nim | 2 -- lib/pure/parsexml.nim | 3 --- lib/pure/pegs.nim | 10 +++---- lib/pure/ropes.nim | 2 -- lib/pure/scgi.nim | 3 --- lib/pure/selectors.nim | 8 +++--- lib/pure/smtp.nim | 2 -- lib/pure/stats.nim | 2 -- lib/pure/streams.nim | 31 ---------------------- lib/pure/strtabs.nim | 19 +++---------- lib/pure/subexes.nim | 3 --- lib/pure/uri.nim | 8 +++--- lib/pure/xmlparser.nim | 2 -- lib/pure/xmltree.nim | 8 ------ 54 files changed, 44 insertions(+), 287 deletions(-) diff --git a/lib/deprecated/pure/ftpclient.nim b/lib/deprecated/pure/ftpclient.nim index ed2f144501..7645258b60 100644 --- a/lib/deprecated/pure/ftpclient.nim +++ b/lib/deprecated/pure/ftpclient.nim @@ -12,7 +12,7 @@ import sockets, strutils, parseutils, times, os, asyncio from asyncnet import nil from nativesockets import nil -from asyncdispatch import PFuture +from asyncdispatch import Future ## **Note**: This module is deprecated since version 0.11.3. ## You should use the async version of this module ## `asyncftpclient `_. diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 223fc836a3..ff2bdb8ce9 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -853,7 +853,6 @@ type DirKind = enum # must be ordered alphabetically! dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents, dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle -{.deprecated: [TDirKind: DirKind].} const DirIds: array[0..12, string] = ["", "author", "authors", "code", @@ -1114,7 +1113,6 @@ proc parseHeadline(p: var RstParser): PRstNode = type IntSeq = seq[int] -{.deprecated: [TIntSeq: IntSeq].} proc tokEnd(p: RstParser): int = result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1 @@ -1408,8 +1406,6 @@ type hasArg, hasOptions, argIsFile, argIsWord DirFlags = set[DirFlag] SectionParser = proc (p: var RstParser): PRstNode {.nimcall.} -{.deprecated: [TDirFlag: DirFlag, TDirFlags: DirFlags, - TSectionParser: SectionParser].} proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode = ## Parses arguments and options for a directive block. diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 7be4470c11..f3596b5713 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -70,8 +70,6 @@ type ## the document or the section level*: int ## valid for some node kinds sons*: RstNodeSeq ## the node's sons -{.deprecated: [TRstNodeKind: RstNodeKind, TRstNodeSeq: RstNodeSeq, - TRstNode: RstNode].} proc len*(n: PRstNode): int = result = len(n.sons) @@ -99,7 +97,6 @@ type RenderContext {.pure.} = object indent: int verbatim: int -{.deprecated: [TRenderContext: RenderContext].} proc renderRstToRst(d: var RenderContext, n: PRstNode, result: var string) {.gcsafe.} diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 5d7348b8dd..6918c178d9 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -13,9 +13,6 @@ type SortOrder* = enum ## sort order Descending, Ascending -{.deprecated: [TSortOrder: SortOrder].} - - proc `*`*(x: int, order: SortOrder): int {.inline.} = ## flips `x` if ``order == Descending``; ## if ``order == Ascending`` then `x` is returned. diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 8fedb16fe9..863a6843be 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -27,8 +27,6 @@ type FutureError* = object of Exception cause*: FutureBase -{.deprecated: [PFutureBase: FutureBase, PFuture: Future].} - when not defined(release): var currentID = 0 diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index ba16156515..fe5a835d74 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -60,9 +60,6 @@ type reusePort: bool maxBody: int ## The maximum content-length that will be read for the body. -{.deprecated: [TRequest: Request, PAsyncHttpServer: AsyncHttpServer, - THttpCode: HttpCode, THttpVersion: HttpVersion].} - proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = ## Creates a new ``AsyncHttpServer`` instance. diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 7c354151b3..e7552e3e3b 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -134,8 +134,6 @@ type protocol: Protocol AsyncSocket* = ref AsyncSocketDesc -{.deprecated: [PAsyncSocket: AsyncSocket].} - proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket = diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index a5a4044970..e0cdc2ec0a 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -64,8 +64,6 @@ type methodPost, ## query uses the POST method methodGet ## query uses the GET method -{.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError].} - proc cgiError*(msg: string) {.noreturn.} = ## raises an ECgi exception with message `msg`. var e: ref CgiError diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 4ec76dee01..25a2fb870e 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -14,8 +14,6 @@ import strutils type Color* = distinct int ## a color stored as RGB -{.deprecated: [TColor: Color].} - proc `==` *(a, b: Color): bool {.borrow.} ## compares two colors. diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index ccde5ee0a8..98cab1a5ae 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -25,8 +25,6 @@ type Complex* = tuple[re, im: float] ## a complex number, consisting of a real and an imaginary part -{.deprecated: [TComplex: Complex].} - proc toComplex*(x: SomeInteger): Complex = ## Convert some integer ``x`` to a complex number. result.re = x diff --git a/lib/pure/db_common.nim b/lib/pure/db_common.nim index 957389605c..f8689024b5 100644 --- a/lib/pure/db_common.nim +++ b/lib/pure/db_common.nim @@ -83,9 +83,6 @@ type foreignKey*: bool ## is this a foreign key? DbColumns* = seq[DbColumn] -{.deprecated: [EDb: DbError, TSqlQuery: SqlQuery, FDb: DbEffect, - FReadDb: ReadDbEffect, FWriteDb: WriteDbEffect].} - template sql*(query: string): SqlQuery = ## constructs a SqlQuery from the string `query`. This is supposed to be ## used as a raw-string-literal modifier: diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index ec6cbb232b..5bd06f6fb3 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -17,9 +17,9 @@ ## Loading a simple C function ## ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ## -## The following example demonstrates loading a function called 'greet' +## The following example demonstrates loading a function called 'greet' ## from a library that is determined at runtime based upon a language choice. -## If the library fails to load or the function 'greet' is not found, +## If the library fails to load or the function 'greet' is not found, ## it quits with a failure error code. ## ## .. code-block::nim @@ -59,8 +59,6 @@ import strutils type LibHandle* = pointer ## a handle to a dynamically loaded library -{.deprecated: [TLibHandle: LibHandle].} - proc loadLib*(path: string, global_symbols=false): LibHandle {.gcsafe.} ## loads a library from `path`. Returns nil if the library could not ## be loaded. diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 731fbbc297..c67cd7579c 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -27,8 +27,6 @@ type EncodingError* = object of ValueError ## exception that is raised ## for encoding errors -{.deprecated: [EInvalidEncoding: EncodingError, PConverter: EncodingConverter].} - when defined(windows): proc eqEncodingNames(a, b: string): bool = var i = 0 diff --git a/lib/pure/events.nim b/lib/pure/events.nim index 23a8a2c58c..a39dbe3bf6 100644 --- a/lib/pure/events.nim +++ b/lib/pure/events.nim @@ -43,9 +43,6 @@ type s: seq[EventHandler] EventError* = object of ValueError -{.deprecated: [TEventArgs: EventArgs, TEventHandler: EventHandler, - TEventEmitter: EventEmitter, EInvalidEvent: EventError].} - proc initEventHandler*(name: string): EventHandler = ## Initializes an EventHandler with the specified name and returns it. result.handlers = @[] diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index b015ed3115..6535bb0d3e 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -45,7 +45,6 @@ type Hash* = int ## a hash value; hash tables using these values should ## always have a size of a power of two and can use the ``and`` ## operator instead of ``mod`` for truncation of the hash value. -{.deprecated: [THash: Hash].} proc `!&`*(h: Hash, val: int): Hash {.inline.} = ## mixes a hash value `h` with `val` to produce a new hash value. This is diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index 2f833804d4..9d4b57dc0b 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -178,7 +178,6 @@ type tagVar, ## the HTML ``var`` element tagVideo, ## the HTML ``video`` element tagWbr ## the HTML ``wbr`` element -{.deprecated: [THtmlTag: HtmlTag].} const tagToStr* = [ diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 91b78f59b2..3f1a3d0671 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -219,10 +219,6 @@ type ## and ``postContent`` proc, ## when the server returns an error -{.deprecated: [TResponse: Response, PProxy: Proxy, - EInvalidProtocol: ProtocolError, EHttpRequestErr: HttpRequestError -].} - const defUserAgent* = "Nim httpclient/" & NimVersion proc httpError(msg: string) = @@ -362,8 +358,6 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response = else: result.body = "" -{.deprecated: [THttpMethod: HttpMethod].} - when not defined(ssl): type SSLContext = ref object var defaultSSLContext {.threadvar.}: SSLContext @@ -585,7 +579,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "", result = parseResponse(s, httpMethod != "HEAD", timeout) -proc request*(url: string, httpMethod = httpGET, extraHeaders = "", +proc request*(url: string, httpMethod = HttpGET, extraHeaders = "", body = "", sslContext = defaultSSLContext, timeout = -1, userAgent = defUserAgent, proxy: Proxy = nil): Response {.deprecated.} = @@ -627,13 +621,13 @@ proc get*(url: string, extraHeaders = "", maxRedirects = 5, ## server takes longer than specified an ETimeout exception will be raised. ## ## **Deprecated since version 0.15.0**: use ``HttpClient.get`` instead. - result = request(url, httpGET, extraHeaders, "", sslContext, timeout, + result = request(url, HttpGET, extraHeaders, "", sslContext, timeout, userAgent, proxy) var lastURL = url for i in 1..maxRedirects: if result.status.redirection(): let redirectTo = getNewLocation(lastURL, result.headers) - result = request(redirectTo, httpGET, extraHeaders, "", sslContext, + result = request(redirectTo, HttpGET, extraHeaders, "", sslContext, timeout, userAgent, proxy) lastURL = redirectTo @@ -687,13 +681,13 @@ proc post*(url: string, extraHeaders = "", body = "", if not multipart.isNil: xh.add(withNewLine("Content-Type: " & mpContentType)) - result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent, + result = request(url, HttpPOST, xh, xb, sslContext, timeout, userAgent, proxy) var lastURL = url for i in 1..maxRedirects: if result.status.redirection(): let redirectTo = getNewLocation(lastURL, result.headers) - var meth = if result.status != "307": httpGet else: httpPost + var meth = if result.status != "307": HttpGet else: HttpPost result = request(redirectTo, meth, xh, xb, sslContext, timeout, userAgent, proxy) lastURL = redirectTo diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 5df26fdd58..f853751110 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -45,10 +45,6 @@ type ## TCP/IP tunnel, usually used for proxies. HttpPatch ## Applies partial modifications to a resource. -{.deprecated: [httpGet: HttpGet, httpHead: HttpHead, httpPost: HttpPost, - httpPut: HttpPut, httpDelete: HttpDelete, httpTrace: HttpTrace, - httpOptions: HttpOptions, httpConnect: HttpConnect].} - const Http100* = HttpCode(100) diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim index 9f54ed9e83..a81e8c0a8d 100644 --- a/lib/pure/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -110,7 +110,6 @@ when false: # TODO: Fix this, or get rid of it. type RequestMethod = enum reqGet, reqPost - {.deprecated: [TRequestMethod: RequestMethod].} proc executeCgi(client: Socket, path, query: string, meth: RequestMethod) = var env = newStringTable(modeCaseInsensitive) @@ -225,7 +224,6 @@ type PAsyncHTTPServer* = ref AsyncHTTPServer AsyncHTTPServer = object of Server asyncSocket: AsyncSocket -{.deprecated: [TAsyncHTTPServer: AsyncHTTPServer, TServer: Server].} proc open*(s: var Server, port = Port(80), reuseAddr = false) = ## creates a new server at port `port`. If ``port == 0`` a free port is diff --git a/lib/pure/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim index 45b10c584a..06f4958c6e 100644 --- a/lib/pure/includes/asynccommon.nim +++ b/lib/pure/includes/asynccommon.nim @@ -18,13 +18,13 @@ proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET, createAsyncNativeSocketImpl(domain, sockType, protocol) proc newAsyncNativeSocket*(domain: cint, sockType: cint, - protocol: cint): AsyncFD {.deprecated.} = + protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} = createAsyncNativeSocketImpl(domain, sockType, protocol) proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET, sockType: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP): AsyncFD - {.deprecated.} = + {.deprecated: "use createAsyncNativeSocket instead".} = createAsyncNativeSocketImpl(domain, sockType, protocol) when defined(windows) or defined(nimdoc): diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim index 0889d73835..bfb6118f24 100644 --- a/lib/pure/includes/oserr.nim +++ b/lib/pure/includes/oserr.nim @@ -12,50 +12,6 @@ when not defined(nimscript): when defined(windows): import winlean -proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} = - ## Retrieves the operating system's error flag, ``errno``. - ## On Windows ``GetLastError`` is checked before ``errno``. - ## Returns "" if no error occurred. - ## - ## **Deprecated since version 0.9.4**: use the other ``osErrorMsg`` proc. - - result = "" - when defined(Windows) and not defined(nimscript): - var err = getLastError() - if err != 0'i32: - when useWinUnicode: - var msgbuf: WideCString - if formatMessageW(0x00000100 or 0x00001000 or 0x00000200 or 0x000000FF, - nil, err, 0, addr(msgbuf), 0, nil) != 0'i32: - result = $msgbuf - if msgbuf != nil: localFree(cast[pointer](msgbuf)) - else: - var msgbuf: cstring - if formatMessageA(0x00000100 or 0x00001000 or 0x00000200 or 0x000000FF, - nil, err, 0, addr(msgbuf), 0, nil) != 0'i32: - result = $msgbuf - if msgbuf != nil: localFree(msgbuf) - when not defined(nimscript): - if errno != 0'i32: - result = $c_strerror(errno) - -{.push warning[deprecated]: off.} -proc raiseOSError*(msg: string = "") {.noinline, rtl, extern: "nos$1", - deprecated.} = - ## raises an OSError exception with the given message ``msg``. - ## If ``msg == ""``, the operating system's error flag - ## (``errno``) is converted to a readable error message. On Windows - ## ``GetLastError`` is checked before ``errno``. - ## If no error flag is set, the message ``unknown OS error`` is used. - ## - ## **Deprecated since version 0.9.4**: use the other ``raiseOSError`` proc. - if len(msg) == 0: - var m = osErrorMsg() - raise newException(OSError, if m.len > 0: m else: "unknown OS error") - else: - raise newException(OSError, msg) -{.pop.} - proc `==`*(err1, err2: OSErrorCode): bool {.borrow.} proc `$`*(err: OSErrorCode): string {.borrow.} diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 574b13fbf2..b16918959c 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -158,9 +158,6 @@ type JsonKindError* = object of ValueError ## raised by the ``to`` macro if the ## JSON kind is incorrect. -{.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError, - TJsonParser: JsonParser, TTokKind: TokKind].} - const errorMessages: array[JsonError, string] = [ "no error", @@ -622,9 +619,6 @@ type JsonParsingError* = object of ValueError ## is raised for a JSON error -{.deprecated: [EJsonParsingError: JsonParsingError, TJsonNode: JsonNodeObj, - PJsonNode: JsonNode, TJsonNodeKind: JsonNodeKind].} - proc raiseParseErr*(p: JsonParser, msg: string) {.noinline, noreturn.} = ## raises an `EJsonParsingError` exception. raise newException(JsonParsingError, errorMsgExpected(p, msg)) @@ -695,7 +689,7 @@ proc getBiggestInt*(n: JsonNode, default: BiggestInt = 0): BiggestInt = if n.isNil or n.kind != JInt: return default else: return n.num -proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated.} = +proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated: "use getInt or getBiggestInt instead".} = ## **Deprecated since v0.18.2:** use ``getInt`` or ``getBiggestInt`` instead. getBiggestInt(n, default) @@ -709,7 +703,7 @@ proc getFloat*(n: JsonNode, default: float = 0.0): float = of JInt: return float(n.num) else: return default -proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated.} = +proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated: "use getFloat instead".} = ## **Deprecated since v0.18.2:** use ``getFloat`` instead. getFloat(n, default) @@ -720,7 +714,7 @@ proc getBool*(n: JsonNode, default: bool = false): bool = if n.isNil or n.kind != JBool: return default else: return n.bval -proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated.} = +proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated: "use getBool instead".} = ## **Deprecated since v0.18.2:** use ``getBool`` instead. getBool(n, default) @@ -946,7 +940,7 @@ proc contains*(node: JsonNode, val: JsonNode): bool = assert(node.kind == JArray) find(node.elems, val) >= 0 -proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key) +proc existsKey*(node: JsonNode, key: string): bool {.deprecated: "use hasKey instead".} = node.hasKey(key) ## **Deprecated:** use `hasKey` instead. proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} = @@ -1277,7 +1271,6 @@ else: from math import `mod` type JSObject = object - {.deprecated: [TJSObject: JSObject].} proc parseNativeJson(x: cstring): JSObject {.importc: "JSON.parse".} diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim index 15a390f0b9..e38acd5ef0 100644 --- a/lib/pure/lexbase.nim +++ b/lib/pure/lexbase.nim @@ -40,8 +40,6 @@ type offsetBase*: int # use ``offsetBase + bufpos`` to get the offset refillChars: set[char] -{.deprecated: [TBaseLexer: BaseLexer].} - const chrSize = sizeof(char) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 43b5ab3aba..cdff1f5484 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -96,10 +96,6 @@ when not defined(js): logFiles: int # how many log files already created, e.g. basename.1, basename.2... bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size) - {.deprecated: [PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].} - -{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger].} - var level {.threadvar.}: Level ## global log filter handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 6ee830786c..b88c9dd858 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -309,7 +309,6 @@ when not defined(testing) and isMainModule: Node = object next, prev: PNode data: string - {.deprecated: [TNode: Node].} proc buildList(): PNode = new(result) diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 5c73381ffb..bf6795b0c2 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -38,8 +38,6 @@ type else: handle: cint -{.deprecated: [TMemFile: MemFile].} - proc mapMem*(m: var MemFile, mode: FileMode = fmRead, mappedSize = -1, offset = 0): pointer = ## returns a pointer to a mapped portion of MemFile `m` diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim index 6ac0c4e56f..b2227f1144 100644 --- a/lib/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -12,8 +12,6 @@ type mt: array[0..623, uint32] index: int -{.deprecated: [TMersenneTwister: MersenneTwister].} - proc newMersenneTwister*(seed: uint32): MersenneTwister = result.index = 0 result.mt[0] = seed diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index b397ef47b5..ff69ba61e2 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -13,8 +13,6 @@ type MimeDB* = object mimes: StringTableRef -{.deprecated: [TMimeDB: MimeDB].} - const mimes* = { "ez": "application/andrew-inset", "anx": "application/annodex", diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 09fa253f12..5545ca2d19 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -85,9 +85,6 @@ type length*: int addrList*: seq[string] -{.deprecated: [TPort: Port, TDomain: Domain, TType: SockType, - TProtocol: Protocol, TServent: Servent, THostent: Hostent].} - when useWinVersion: let osInvalidSocket* = winlean.INVALID_SOCKET @@ -640,7 +637,7 @@ proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) = inc(i) setLen(s, L) -proc select*(readfds: var seq[SocketHandle], timeout = 500): int {.deprecated.} = +proc select*(readfds: var seq[SocketHandle], timeout = 500): int {.deprecated: "use selectRead instead".} = ## When a socket in ``readfds`` is ready to be read from then a non-zero ## value will be returned specifying the count of the sockets which can be ## read from. The sockets which can be read from will also be removed diff --git a/lib/pure/net.nim b/lib/pure/net.nim index e522d86fef..06bf126655 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -110,9 +110,6 @@ when defineSsl: serverGetPskFunc: SslServerGetPskFunc clientGetPskFunc: SslClientGetPskFunc - {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode, - TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext, - TSSLAcceptResult: SSLAcceptResult].} else: type SslContext* = void # TODO: Workaround #4797. @@ -159,10 +156,6 @@ type Peek, SafeDisconn ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown. -{.deprecated: [TSocketFlags: SocketFlag, ETimeout: TimeoutError, - TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket, - TSocketImpl: SocketImpl].} - type IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address IPv6, ## IPv6 address @@ -176,8 +169,6 @@ type of IpAddressFamily.IPv4: address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in ## case of IPv4 -{.deprecated: [TIpAddress: IpAddress].} - proc socketError*(socket: Socket, err: int = -1, async = false, lastError = (-1).OSErrorCode): void {.gcsafe.} diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 4289eb049c..506c6bfaab 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -30,7 +30,6 @@ when not declared(system.StackTrace): type StackTrace = object lines: array[0..20, cstring] files: array[0..20, cstring] - {.deprecated: [TStackTrace: StackTrace].} proc `[]`*(st: StackTrace, i: int): cstring = st.lines[i] # We use a simple hash table of bounded size to keep track of the stack traces: @@ -39,7 +38,6 @@ type total: int st: StackTrace ProfileData = array[0..64*1024-1, ptr ProfileEntry] -{.deprecated: [TProfileEntry: ProfileEntry, TProfileData: ProfileData].} proc `==`(a, b: StackTrace): bool = for i in 0 .. high(a.lines): diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index 26a55de6cc..d6369b5f9f 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -23,11 +23,9 @@ type fuzz: int32 ## count: int32 ## -{.deprecated: [Toid: Oid].} - proc `==`*(oid1: Oid, oid2: Oid): bool = - ## Compare two Mongo Object IDs for equality - return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count) + ## Compare two Mongo Object IDs for equality + return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count) proc hexbyte*(hex: char): int = case hex diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 644afee325..03445a0353 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -431,8 +431,6 @@ type fpOthersWrite, ## write access for others fpOthersRead ## read access for others -{.deprecated: [TFilePermission: FilePermission].} - proc getFilePermissions*(filename: string): set[FilePermission] {. rtl, extern: "nos$1", tags: [ReadDirEffect].} = ## retrieves file permissions for `filename`. `OSError` is raised in case of @@ -730,8 +728,6 @@ type pcDir, ## path refers to a directory pcLinkToDir ## path refers to a symbolic link to a directory -{.deprecated: [TPathComponent: PathComponent].} - when defined(posix): proc getSymlinkFileKind(path: string): PathComponent = @@ -1441,18 +1437,6 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = if result.len == 0: result = getApplHeuristic() -proc getApplicationFilename*(): string {.rtl, extern: "nos$1", deprecated.} = - ## Returns the filename of the application's executable. - ## **Deprecated since version 0.8.12**: use ``getAppFilename`` - ## instead. - result = getAppFilename() - -proc getApplicationDir*(): string {.rtl, extern: "nos$1", deprecated.} = - ## Returns the directory of the application's executable. - ## **Deprecated since version 0.8.12**: use ``getAppDir`` - ## instead. - result = splitFile(getAppFilename()).dir - proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = ## Returns the directory of the application's executable. result = splitFile(getAppFilename()).dir diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index ee2b715d3a..c0d3ef5127 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -29,11 +29,6 @@ type OSErrorCode* = distinct int32 ## Specifies an OS Error Code. -{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect, - FReadDir: ReadDirEffect, - FWriteDir: WriteDirEffect, - TOSErrorCode: OSErrorCode -].} const doslikeFileSystem* = defined(windows) or defined(OS2) or defined(DOS) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index bcab5ad3ae..664446d546 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -61,9 +61,6 @@ type Process* = ref ProcessObj ## represents an operating system process -{.deprecated: [TProcess: ProcessObj, PProcess: Process, - TProcessOption: ProcessOption].} - const poUseShell* {.deprecated.} = poUsePath ## Deprecated alias for poUsePath. @@ -373,17 +370,15 @@ template streamAccess(p) = when defined(Windows) and not defined(useNimRtl): # We need to implement a handle stream for Windows: type - PFileHandleStream = ref FileHandleStream - FileHandleStream = object of StreamObj + FileHandleStream = ref object of StreamObj handle: Handle atTheEnd: bool - {.deprecated: [TFileHandleStream: FileHandleStream].} proc hsClose(s: Stream) = discard # nothing to do here - proc hsAtEnd(s: Stream): bool = return PFileHandleStream(s).atTheEnd + proc hsAtEnd(s: Stream): bool = return FileHandleStream(s).atTheEnd proc hsReadData(s: Stream, buffer: pointer, bufLen: int): int = - var s = PFileHandleStream(s) + var s = FileHandleStream(s) if s.atTheEnd: return 0 var br: int32 var a = winlean.readFile(s.handle, buffer, bufLen.cint, addr br, nil) @@ -395,13 +390,13 @@ when defined(Windows) and not defined(useNimRtl): result = br proc hsWriteData(s: Stream, buffer: pointer, bufLen: int) = - var s = PFileHandleStream(s) + var s = FileHandleStream(s) var bytesWritten: int32 var a = winlean.writeFile(s.handle, buffer, bufLen.cint, addr bytesWritten, nil) if a == 0: raiseOSError(osLastError()) - proc newFileHandleStream(handle: Handle): PFileHandleStream = + proc newFileHandleStream(handle: Handle): FileHandleStream = new(result) result.handle = handle result.closeImpl = hsClose @@ -527,7 +522,7 @@ when defined(Windows) and not defined(useNimRtl): if setHandleInformation(he, DWORD(1), DWORD(0)) == 0'i32: raiseOsError(osLastError()) if setHandleInformation(hi, DWORD(1), DWORD(0)) == 0'i32: - raiseOsError(osLastError()) + raiseOsError(osLastError()) if setHandleInformation(ho, DWORD(1), DWORD(0)) == 0'i32: raiseOsError(osLastError()) else: @@ -752,14 +747,14 @@ elif not defined(useNimRtl): copyMem(result[i], addr(x[0]), x.len+1) inc(i) - type StartProcessData = object - sysCommand: string - sysArgs: cstringArray - sysEnv: cstringArray - workingDir: cstring - pStdin, pStdout, pStderr, pErrorPipe: array[0..1, cint] - options: set[ProcessOption] - {.deprecated: [TStartProcessData: StartProcessData].} + type + StartProcessData = object + sysCommand: string + sysArgs: cstringArray + sysEnv: cstringArray + workingDir: cstring + pStdin, pStdout, pStderr, pErrorPipe: array[0..1, cint] + options: set[ProcessOption] const useProcessAuxSpawn = declared(posix_spawn) and not defined(useFork) and not defined(useClone) and not defined(linux) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 2a5dbc8f8c..5fa2d8dc3d 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -125,9 +125,6 @@ type tok: Token filename: string -{.deprecated: [TCfgEventKind: CfgEventKind, TCfgEvent: CfgEvent, - TTokKind: TokKind, TToken: Token, TCfgParser: CfgParser].} - # implementation const diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index 358ce829d1..796114d37d 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -66,8 +66,6 @@ type CsvError* = object of IOError ## exception that is raised if ## a parsing error occurs -{.deprecated: [TCsvRow: CsvRow, TCsvParser: CsvParser, EInvalidCsv: CsvError].} - proc raiseEInvalidCsv(filename: string, line, col: int, msg: string) {.noreturn.} = var e: ref CsvError diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index c1a6161f9e..58e1be0e41 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -54,8 +54,6 @@ type ## or the argument, ``value`` is not "" if ## the option was given a value -{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].} - proc parseWord(s: string, i: int, w: var string, delim: set[char] = {'\x09', ' '}): int = result = i diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim index 7254337d09..b54a56c0c5 100644 --- a/lib/pure/parseopt2.nim +++ b/lib/pure/parseopt2.nim @@ -41,8 +41,6 @@ type ## or the argument, ``value`` is not "" if ## the option was given a value -{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].} - proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} = ## Initalizes option parses with cmdline. cmdline should not contain ## argument 0 - program name. @@ -122,8 +120,6 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo2$1", deprecat type GetoptResult* = tuple[kind: CmdLineKind, key, val: TaintedString] -{.deprecated: [TGetoptResult: GetoptResult].} - iterator getopt*(p: var OptParser): GetoptResult = ## This is an convenience iterator for iterating over the given OptParser object. ## Example: diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index fcc757bea2..e3bab9a8d2 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -45,8 +45,6 @@ type SqlLexer* = object of BaseLexer ## the parser object. filename: string -{.deprecated: [TToken: Token, TSqlLexer: SqlLexer].} - const tokKindToStr: array[TokKind, string] = [ "invalid", "[EOF]", "identifier", "quoted identifier", "string constant", diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 1d76234ea0..d77790fe02 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -365,8 +365,6 @@ type ikVar, ## ``var`` part of the interpolated string ikExpr ## ``expr`` part of the interpolated string -{.deprecated: [TInterpolatedKind: InterpolatedKind].} - iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, value: string] = ## Tokenizes the string `s` into substrings for interpolation purposes. diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 978c9c5161..e0000aad31 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -98,9 +98,6 @@ type filename: string options: set[XmlParseOption] -{.deprecated: [TXmlParser: XmlParser, TXmlParseOptions: XmlParseOption, - TXmlError: XmlErrorKind, TXmlEventKind: XmlEventKind].} - const errorMessages: array[XmlErrorKind, string] = [ "no error", diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 6d415efd06..6355c4899c 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -74,8 +74,8 @@ type line: int ## line the symbol has been declared/used in col: int ## column the symbol has been declared/used in flags: set[NonTerminalFlag] ## the nonterminal's flags - rule: Node ## the rule that the symbol refers to - Node {.shallow.} = object + rule: Peg ## the rule that the symbol refers to + Peg* {.shallow.} = object ## type that represents a PEG case kind: PegKind of pkEmpty..pkWhitespace: nil of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string @@ -83,13 +83,9 @@ type of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char] of pkNonTerminal: nt: NonTerminal of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns] - else: sons: seq[Node] + else: sons: seq[Peg] NonTerminal* = ref NonTerminalObj - Peg* = Node ## type that represents a PEG - -{.deprecated: [TPeg: Peg, TNode: Node].} - proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} = ## constructs a PEG from a terminal string if t.len != 1: diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 24ba012e5f..9b9cdb52a9 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -37,8 +37,6 @@ type length: int data: string # != nil if a leaf -{.deprecated: [PRope: Rope].} - proc isConc(r: Rope): bool {.inline.} = return isNil(r.data) # Note that the left and right pointers are not needed for leafs. diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim index 1ff26954e6..e36803823a 100644 --- a/lib/pure/scgi.nim +++ b/lib/pure/scgi.nim @@ -94,9 +94,6 @@ type disp: Dispatcher AsyncScgiState* = ref AsyncScgiStateObj -{.deprecated: [EScgi: ScgiError, TScgiState: ScgiState, - PAsyncScgiState: AsyncScgiState].} - proc recvBuffer(s: var ScgiState, L: int) = if L > s.bufLen: s.bufLen = L diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index dda5658a2d..640df8282a 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -271,7 +271,7 @@ else: msg.add("Internal Error\n") var err = newException(IOSelectorsException, msg) raise err - + proc setNonBlocking(fd: cint) {.inline.} = setBlocking(fd.SocketHandle, false) @@ -316,18 +316,18 @@ else: include ioselects/ioselectors_poll proc register*[T](s: Selector[T], fd: int | SocketHandle, - events: set[Event], data: T) {.deprecated.} = + events: set[Event], data: T) {.deprecated: "use registerHandle instead".} = ## **Deprecated since v0.18.0:** Use ``registerHandle`` instead. s.registerHandle(fd, events, data) -proc setEvent*(ev: SelectEvent) {.deprecated.} = +proc setEvent*(ev: SelectEvent) {.deprecated: "use trigger instead".} = ## Trigger event ``ev``. ## ## **Deprecated since v0.18.0:** Use ``trigger`` instead. ev.trigger() proc update*[T](s: Selector[T], fd: int | SocketHandle, - events: set[Event]) {.deprecated.} = + events: set[Event]) {.deprecated: "use updateHandle instead".} = ## Update file/socket descriptor ``fd``, registered in selector ## ``s`` with new events set ``event``. ## diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 08e6c81125..c2c674b844 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -51,8 +51,6 @@ type Smtp* = SmtpBase[Socket] AsyncSmtp* = SmtpBase[AsyncSocket] -{.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].} - proc debugSend(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = if smtp.debug: echo("C:" & cmd) diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index 9649381333..ce32108c27 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -65,8 +65,6 @@ type y_stats*: RunningStat ## stats for second set of data s_xy: float ## accumulated data for combined xy -{.deprecated: [TFloatClass: FloatClass, TRunningStat: RunningStat].} - # ----------- RunningStat -------------------------- proc clear*(s: var RunningStat) = ## reset `s` diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 8fb14b6f6b..68922f7301 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -57,8 +57,6 @@ type tags: [WriteIOEffect], gcsafe.} flushImpl*: proc (s: Stream) {.nimcall, tags: [WriteIOEffect], gcsafe.} -{.deprecated: [PStream: Stream, TStream: StreamObj].} - proc flush*(s: Stream) = ## flushes the buffers that the stream `s` might use. if not isNil(s.flushImpl): s.flushImpl(s) @@ -76,27 +74,14 @@ proc atEnd*(s: Stream): bool = ## been read. result = s.atEndImpl(s) -proc atEnd*(s, unused: Stream): bool {.deprecated.} = - ## checks if more data can be read from `f`. Returns true if all data has - ## been read. - result = s.atEndImpl(s) - proc setPosition*(s: Stream, pos: int) = ## sets the position `pos` of the stream `s`. s.setPositionImpl(s, pos) -proc setPosition*(s, unused: Stream, pos: int) {.deprecated.} = - ## sets the position `pos` of the stream `s`. - s.setPositionImpl(s, pos) - proc getPosition*(s: Stream): int = ## retrieves the current position in the stream `s`. result = s.getPositionImpl(s) -proc getPosition*(s, unused: Stream): int {.deprecated.} = - ## retrieves the current position in the stream `s`. - result = s.getPositionImpl(s) - proc readData*(s: Stream, buffer: pointer, bufLen: int): int = ## low level proc that reads data into an untyped `buffer` of `bufLen` size. result = s.readDataImpl(s, buffer, bufLen) @@ -114,11 +99,6 @@ proc readAll*(s: Stream): string = inc r, bufferSize setLen(result, r+bufferSize) -proc readData*(s, unused: Stream, buffer: pointer, - bufLen: int): int {.deprecated.} = - ## low level proc that reads data into an untyped `buffer` of `bufLen` size. - result = s.readDataImpl(s, buffer, bufLen) - proc peekData*(s: Stream, buffer: pointer, bufLen: int): int = ## low level proc that reads data into an untyped `buffer` of `bufLen` size ## without moving stream position @@ -153,11 +133,6 @@ proc write*(s: Stream, x: string) = else: if x.len > 0: writeData(s, unsafeAddr x[0], x.len) -proc writeLn*(s: Stream, args: varargs[string, `$`]) {.deprecated.} = - ## **Deprecated since version 0.11.4:** Use **writeLine** instead. - for str in args: write(s, str) - write(s, "\n") - proc writeLine*(s: Stream, args: varargs[string, `$`]) = ## writes one or more strings to the the stream `s` followed ## by a new line. No length field or terminating zero is written. @@ -348,8 +323,6 @@ when not defined(js): data*: string pos: int - {.deprecated: [PStringStream: StringStream, TStringStream: StringStreamObj].} - proc ssAtEnd(s: Stream): bool = var s = StringStream(s) return s.pos >= s.data.len @@ -409,7 +382,6 @@ when not defined(js): FileStream* = ref FileStreamObj ## a stream that encapsulates a `File` FileStreamObj* = object of Stream f: File - {.deprecated: [PFileStream: FileStream, TFileStream: FileStreamObj].} proc fsClose(s: Stream) = if FileStream(s).f != nil: @@ -472,9 +444,6 @@ else: handle*: FileHandle pos: int - {.deprecated: [PFileHandleStream: FileHandleStream, - TFileHandleStream: FileHandleStreamObj].} - proc newEOS(msg: string): ref OSError = new(result) result.msg = msg diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 75f9b42cd0..d8a23286a5 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -17,9 +17,7 @@ import when defined(js): {.pragma: rtlFunc.} - {.pragma: deprecatedGetFunc.} else: - {.pragma: deprecatedGetFunc, deprecatedGet.} {.pragma: rtlFunc, rtl.} import os include "system/inclrtl" @@ -38,9 +36,6 @@ type StringTableRef* = ref StringTableObj ## use this type to declare string tables -{.deprecated: [TStringTableMode: StringTableMode, - TStringTable: StringTableObj, PStringTable: StringTableRef].} - proc len*(t: StringTableRef): int {.rtlFunc, extern: "nst$1".} = ## returns the number of keys in `t`. result = t.counter @@ -73,10 +68,6 @@ type useKey ## do not replace ``$key`` if it is not found ## in the table (or in the environment) -{.deprecated: [TFormatFlag: FormatFlag].} - -# implementation - const growthFactor = 2 startSize = 64 @@ -118,17 +109,12 @@ template get(t: StringTableRef, key: string) = raise newException(KeyError, "key not found") proc `[]`*(t: StringTableRef, key: string): var string {. - rtlFunc, extern: "nstTake", deprecatedGetFunc.} = + rtlFunc, extern: "nstTake".} = ## retrieves the location at ``t[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. get(t, key) -proc mget*(t: StringTableRef, key: string): var string {.deprecated.} = - ## retrieves the location at ``t[key]``. If `key` is not in `t`, the - ## ``KeyError`` exception is raised. Use ```[]``` instead. - get(t, key) - proc getOrDefault*(t: StringTableRef; key: string, default: string = ""): string = var index = rawGet(t, key) if index >= 0: result = t.data[index].val @@ -193,7 +179,8 @@ proc newStringTable*(mode: StringTableMode): StringTableRef {. result.counter = 0 newSeq(result.data, startSize) -proc clear*(s: StringTableRef, mode: StringTableMode) = +proc clear*(s: StringTableRef, mode: StringTableMode) {. + rtlFunc, extern: "nst$1".} = ## resets a string table to be empty again. s.mode = mode s.counter = 0 diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim index 9d807abd4e..8149c72cc1 100644 --- a/lib/pure/subexes.nim +++ b/lib/pure/subexes.nim @@ -31,8 +31,6 @@ type SubexError* = object of ValueError ## exception that is raised for ## an invalid subex -{.deprecated: [EInvalidSubex: SubexError].} - proc raiseInvalidFormat(msg: string) {.noinline.} = raise newException(SubexError, "invalid format string: " & msg) @@ -44,7 +42,6 @@ type else: f: cstring num, i, lineLen: int -{.deprecated: [TFormatParser: FormatParser].} template call(x: untyped): untyped = p.i = i diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 36ab00580f..dd80409283 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -18,14 +18,12 @@ type hostname*, port*, path*, query*, anchor*: string opaque*: bool -{.deprecated: [TUrl: Url, TUri: Uri].} - {.push warning[deprecated]: off.} -proc `$`*(url: Url): string {.deprecated.} = +proc `$`*(url: Url): string {.deprecated: "use Uri instead".} = ## **Deprecated since 0.9.6**: Use ``Uri`` instead. return string(url) -proc `/`*(a, b: Url): Url {.deprecated.} = +proc `/`*(a, b: Url): Url {.deprecated: "use Uri instead".} = ## Joins two URLs together, separating them with / if needed. ## ## **Deprecated since 0.9.6**: Use ``Uri`` instead. @@ -40,7 +38,7 @@ proc `/`*(a, b: Url): Url {.deprecated.} = urlS.add(bs) result = Url(urlS) -proc add*(url: var Url, a: Url) {.deprecated.} = +proc add*(url: var Url, a: Url) {.deprecated: "use Uri instead".} = ## Appends url to url. ## ## **Deprecated since 0.9.6**: Use ``Uri`` instead. diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim index 9159b4bfca..597b80eb5a 100644 --- a/lib/pure/xmlparser.nim +++ b/lib/pure/xmlparser.nim @@ -16,8 +16,6 @@ type ## for invalid XML. errors*: seq[string] ## All detected parsing errors. -{.deprecated: [EInvalidXml: XmlError].} - proc raiseInvalidXml(errors: seq[string]) = var e: ref XmlError new(e) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 20bec300f8..8f85cb5c98 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -33,9 +33,6 @@ type fAttr: XmlAttributes fClientData: int ## for other clients -{.deprecated: [PXmlNode: XmlNode, TXmlNodeKind: XmlNodeKind, PXmlAttributes: - XmlAttributes, TXmlNode: XmlNodeObj].} - proc newXmlNode(kind: XmlNodeKind): XmlNode = ## creates a new ``XmlNode``. new(result) @@ -155,11 +152,6 @@ proc `[]`* (n: var XmlNode, i: int): var XmlNode {.inline.} = assert n.k == xnElement result = n.s[i] -proc mget*(n: var XmlNode, i: int): var XmlNode {.inline, deprecated.} = - ## returns the `i`'th child of `n` so that it can be modified. Use ```[]``` - ## instead. - n[i] - iterator items*(n: XmlNode): XmlNode {.inline.} = ## iterates over any child of `n`. assert n.k == xnElement From d8fde9daba32019a35933cb97f482de5cf3669fa Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 11:55:53 +0200 Subject: [PATCH 142/214] make tests green --- tests/async/tasyncawait.nim | 12 ++++++------ tests/collections/thashes.nim | 4 ++-- tests/exprs/tstmtexprs.nim | 2 +- tests/misc/tsimplesort.nim | 10 +++++----- tests/trmacros/thoist.nim | 2 +- tests/typerel/texplicitcmp.nim | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index 9fe9507adc..74933f0634 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -12,11 +12,11 @@ const var clientCount = 0 -proc sendMessages(client: TAsyncFD) {.async.} = +proc sendMessages(client: AsyncFD) {.async.} = for i in 0 .. counter) result = (length * 2 < counter * 3) or (length - counter < 4) -proc nextTry(h, maxHash: THash): THash {.inline.} = +proc nextTry(h, maxHash: Hash): Hash {.inline.} = result = ((5 * h) + 1) and maxHash template rawGetImpl() = - var h: THash = hash(key) and high(t.data) # start with real hash value + var h: Hash = hash(key) and high(t.data) # start with real hash value while t.data[h].slot != seEmpty: if t.data[h].key == key and t.data[h].slot == seFilled: return h @@ -52,7 +52,7 @@ template rawGetImpl() = result = -1 template rawInsertImpl() = - var h: THash = hash(key) and high(data) + var h: Hash = hash(key) and high(data) while data[h].slot == seFilled: h = nextTry(h, high(data)) data[h].key = key @@ -162,7 +162,7 @@ iterator values*[A](t: TCountTable[A]): int = if t.data[h].val != 0: yield t.data[h].val proc RawGet[A](t: TCountTable[A], key: A): int = - var h: THash = hash(key) and high(t.data) # start with real hash value + var h: Hash = hash(key) and high(t.data) # start with real hash value while t.data[h].val != 0: if t.data[h].key == key: return h h = nextTry(h, high(t.data)) @@ -181,7 +181,7 @@ proc hasKey*[A](t: TCountTable[A], key: A): bool = proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]], key: A, val: int) = - var h: THash = hash(key) and high(data) + var h: Hash = hash(key) and high(data) while data[h].val != 0: h = nextTry(h, high(data)) data[h].key = key data[h].val = val diff --git a/tests/trmacros/thoist.nim b/tests/trmacros/thoist.nim index 7d14c0abf0..657f210a17 100644 --- a/tests/trmacros/thoist.nim +++ b/tests/trmacros/thoist.nim @@ -5,7 +5,7 @@ true''' import pegs -template optPeg{peg(pattern)}(pattern: string{lit}): TPeg = +template optPeg{peg(pattern)}(pattern: string{lit}): Peg = var gl {.global, gensym.} = peg(pattern) gl diff --git a/tests/typerel/texplicitcmp.nim b/tests/typerel/texplicitcmp.nim index 8aec9885ab..e91ac2ffe6 100644 --- a/tests/typerel/texplicitcmp.nim +++ b/tests/typerel/texplicitcmp.nim @@ -18,7 +18,7 @@ proc works() = sort(f, system.cmp[int]) outp(f) -proc weird(json_params: TTable) = +proc weird(json_params: Table) = var f = @[3, 2, 1] # The following line doesn't compile: type mismatch. Why? sort(f, system.cmp[int]) @@ -29,4 +29,4 @@ when isMainModule: sort(t, system.cmp[int]) outp(t) works() - weird(initTable[string, TJsonNode]()) + weird(initTable[string, JsonNode]()) From cd0985df0688c0e5ad6b1c867b41bbd6bbbc88ca Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 08:17:32 +0200 Subject: [PATCH 143/214] update the changelog --- changelog.md | 3 + tests/parser/tbraces.nim | 432 --------------------------------------- 2 files changed, 3 insertions(+), 432 deletions(-) delete mode 100644 tests/parser/tbraces.nim diff --git a/changelog.md b/changelog.md index ba7e0ba5d6..9af2aae83a 100644 --- a/changelog.md +++ b/changelog.md @@ -41,6 +41,9 @@ #### Breaking changes in the compiler +- The undocumented ``#? braces`` parsing mode was removed. +- The undocumented PHP backend was removed. + ### Library additions - ``re.split`` now also supports the ``maxsplit`` parameter for consistency diff --git a/tests/parser/tbraces.nim b/tests/parser/tbraces.nim deleted file mode 100644 index 86c854546f..0000000000 --- a/tests/parser/tbraces.nim +++ /dev/null @@ -1,432 +0,0 @@ -#? braces - -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements some common generic algorithms. - -type - SortOrder* = enum { ## sort order - Descending, Ascending - } - - -type( - DummyAlias = int - OtherAlias = distinct char - - SomeObject = object of RootObj { ## declaration here - fieldA, fieldB: int - case order: SortOrder { - of Descending {a: string} - of Ascending {b: seq[char]} - } - } - - MyConcept = concept x { - x is int - } -) - -{.deprecated: [TSortOrder: SortOrder].} - - -proc `*`*(x: int, order: SortOrder): int @inline { - ## flips `x` if ``order == Descending``; - ## if ``order == Ascending`` then `x` is returned. - ## `x` is supposed to be the result of a comparator, ie ``< 0`` for - ## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*. - var y = order.ord - 1 - result = (x xor y) - y -} - -proc fill*[T](a: var openArray[T], first, last: Natural, value: T) { - ## fills the array ``a[first..last]`` with `value`. - var x = first - while x <= last { - a[x] = value - inc(x) - } -} - -proc fill*[T](a: var openArray[T], value: T) { - ## fills the array `a` with `value`. - fill(a, 0, a.high, value) -} - -proc reverse*[T](a: var openArray[T], first, last: Natural) { - ## reverses the array ``a[first..last]``. - var x = first - var y = last - while x < y { - swap(a[x], a[y]) - dec(y) - inc(x) - } -} - -proc reverse*[T](a: var openArray[T]) { - ## reverses the array `a`. - reverse(a, 0, a.high) -} - -proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] { - ## returns the reverse of the array `a[first..last]`. - assert last >= first-1 - var i = last - first - var x = first.int - result = newSeq[T](i + 1) - while i >= 0 { - result[i] = a[x] - dec(i) - inc(x) - } -} - -proc reversed*[T](a: openArray[T]): seq[T] { - ## returns the reverse of the array `a`. - reversed(a, 0, a.high) -} - -proc binarySearch*[T](a: openArray[T], key: T): int { - ## binary search for `key` in `a`. Returns -1 if not found. - var b = len(a) - while result < b { - var mid = (result + b) div 2 - if a[mid] < key { result = mid + 1 } else { b = mid } - } - if result >= len(a) or a[result] != key { result = -1 } -} - -proc smartBinarySearch*[T](a: openArray[T], key: T): int { - ## ``a.len`` must be a power of 2 for this to work. - var step = a.len div 2 - while step > 0 { - if a[result or step] <= key { result = result or step } - step = step shr 1 - } - if a[result] != key { result = -1 } -} - -const ( - onlySafeCode = true -) - -proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int @closure): int { - ## same as binarySearch except that if key is not in `a` then this - ## returns the location where `key` would be if it were. In other - ## words if you have a sorted sequence and you call - ## insert(thing, elm, lowerBound(thing, elm)) - ## the sequence will still be sorted. - ## - ## `cmp` is the comparator function to use, the expected return values are - ## the same as that of system.cmp. - ## - ## example:: - ## - ## var arr = @[1,2,3,5,6,7,8,9] - ## arr.insert(4, arr.lowerBound(4)) - ## # after running the above arr is `[1,2,3,4,5,6,7,8,9]` - result = a.low - var count = a.high - a.low + 1 - var step, pos: int - while count != 0 { - step = count div 2 - pos = result + step - if cmp(a[pos], key) < 0 { - result = pos + 1 - count -= step + 1 - } else { - count = step - } - } -} - -proc lowerBound*[T](a: openArray[T], key: T): int { lowerBound(a, key, cmp[T]) } -proc merge[T](a, b: var openArray[T], lo, m, hi: int, - cmp: proc (x, y: T): int @closure, order: SortOrder) { - template `<-` (a, b) { - when false { - a = b - } elif onlySafeCode { - shallowCopy(a, b) - } else { - copyMem(addr(a), addr(b), sizeof(T)) - } - } - # optimization: If max(left) <= min(right) there is nothing to do! - # 1 2 3 4 ## 5 6 7 8 - # -> O(n) for sorted arrays. - # On random data this safes up to 40% of merge calls - if cmp(a[m], a[m+1]) * order <= 0 { return } - var j = lo - # copy a[j..m] into b: - assert j <= m - when onlySafeCode { - var bb = 0 - while j <= m { - b[bb] <- a[j] - inc(bb) - inc(j) - } - } else { - copyMem(addr(b[0]), addr(a[j]), sizeof(T)*(m-j+1)) - j = m+1 - } - var i = 0 - var k = lo - # copy proper element back: - while k < j and j <= hi { - if cmp(b[i], a[j]) * order <= 0 { - a[k] <- b[i] - inc(i) - } else { - a[k] <- a[j] - inc(j) - } - inc(k) - } - # copy rest of b: - when onlySafeCode { - while k < j { - a[k] <- b[i] - inc(k) - inc(i) - } - } else { - if k < j { copyMem(addr(a[k]), addr(b[i]), sizeof(T)*(j-k)) } - } -} - -proc sort*[T](a: var openArray[T], - cmp: proc (x, y: T): int @closure, - order = SortOrder.Ascending) { - ## Default Nim sort (an implementation of merge sort). The sorting - ## is guaranteed to be stable and the worst case is guaranteed to - ## be O(n log n). - ## The current implementation uses an iterative - ## mergesort to achieve this. It uses a temporary sequence of - ## length ``a.len div 2``. Currently Nim does not support a - ## sensible default argument for ``cmp``, so you have to provide one - ## of your own. However, the ``system.cmp`` procs can be used: - ## - ## .. code-block:: nim - ## - ## sort(myIntArray, system.cmp[int]) - ## - ## # do not use cmp[string] here as we want to use the specialized - ## # overload: - ## sort(myStrArray, system.cmp) - ## - ## You can inline adhoc comparison procs with the `do notation - ## `_. Example: - ## - ## .. code-block:: nim - ## - ## people.sort do (x, y: Person) -> int: - ## result = cmp(x.surname, y.surname) - ## if result == 0: - ## result = cmp(x.name, y.name) - var n = a.len - var b: seq[T] - newSeq(b, n div 2) - var s = 1 - while s < n { - var m = n-1-s - while m >= 0 { - merge(a, b, max(m-s+1, 0), m, m+s, cmp, order) - dec(m, s*2) - } - s = s*2 - } -} - -proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, - order = SortOrder.Ascending): seq[T] { - ## returns `a` sorted by `cmp` in the specified `order`. - result = newSeq[T](a.len) - for i in 0 .. a.high { result[i] = a[i] } - sort(result, cmp, order) -} - -template sortedByIt*(seq1, op: untyped): untyped { - ## Convenience template around the ``sorted`` proc to reduce typing. - ## - ## The template injects the ``it`` variable which you can use directly in an - ## expression. Example: - ## - ## .. code-block:: nim - ## - ## type Person = tuple[name: string, age: int] - ## var - ## p1: Person = (name: "p1", age: 60) - ## p2: Person = (name: "p2", age: 20) - ## p3: Person = (name: "p3", age: 30) - ## p4: Person = (name: "p4", age: 30) - ## people = @[p1,p2,p4,p3] - ## - ## echo people.sortedByIt(it.name) - ## - ## Because the underlying ``cmp()`` is defined for tuples you can do - ## a nested sort like in the following example: - ## - ## .. code-block:: nim - ## - ## echo people.sortedByIt((it.age, it.name)) - ## - var result = sorted(seq1, proc(x, y: type[seq1[0]]): int { - var it {.inject.} = x - let a = op - it = y - let b = op - result = cmp(a, b) - }) - result -} - -proc isSorted*[T](a: openarray[T], - cmp: proc(x, y: T): int {.closure.}, - order = SortOrder.Ascending): bool { - ## Checks to see whether `a` is already sorted in `order` - ## using `cmp` for the comparison. Parameters identical - ## to `sort` - result = true - for i in 0.. 0 { - of true { return false } - of false {} - } - } -} - -proc product*[T](x: openArray[seq[T]]): seq[seq[T]] { - ## produces the Cartesian product of the array. Warning: complexity - ## may explode. - result = newSeq[seq[T]]() - if x.len == 0 { return } - if x.len == 1 { - result = @x - return - } - var ( - indexes = newSeq[int](x.len) - initial = newSeq[int](x.len) - index = 0 - ) - var next = newSeq[T]() - next.setLen(x.len) - for i in 0..(x.len-1) { - if len(x[i]) == 0 { return } - initial[i] = len(x[i])-1 - } - indexes = initial - while true { - while indexes[index] == -1 { - indexes[index] = initial[index] - index += 1 - if index == x.len { return } - indexes[index] -= 1 - } - for ni, i in indexes { - next[ni] = x[ni][i] - } - var res: seq[T] - shallowCopy(res, next) - result.add(res) - index = 0 - indexes[index] -= 1 - } -} - -proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} { - ## Calculates the next lexicographic permutation, directly modifying ``x``. - ## The result is whether a permutation happened, otherwise we have reached - ## the last-ordered permutation. - ## - ## .. code-block:: nim - ## - ## var v = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - ## v.nextPermutation() - ## echo v # @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8] - if x.len < 2 { - return false } - - var i = x.high - while i > 0 and x[i-1] >= x[i] { dec i } - if i == 0 { return false } - - var j = x.high - while j >= i and x[j] <= x[i-1] { dec j } - - swap x[j], x[i-1] - x.reverse(i, x.high) - - result = true -} - -proc prevPermutation*[T](x: var openarray[T]): bool @discardable { - ## Calculates the previous lexicographic permutation, directly modifying - ## ``x``. The result is whether a permutation happened, otherwise we have - ## reached the first-ordered permutation. - ## - ## .. code-block:: nim - ## - ## var v = @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8] - ## v.prevPermutation() - ## echo v # @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - if x.len < 2 { return false } - - var i = x.high - while i > 0 and x[i-1] <= x[i] { - dec i - } - if i == 0 { return false } - - x.reverse(i, x.high) - - var j = x.high - while j >= i and x[j-1] < x[i-1] { - dec j - } - swap x[i-1], x[j] - - result = true -} - -when isMainModule { - # Tests for lowerBound - var arr = @[1,2,3,5,6,7,8,9] - assert arr.lowerBound(0) == 0 - assert arr.lowerBound(4) == 3 - assert arr.lowerBound(5) == 3 - assert arr.lowerBound(10) == 8 - arr = @[1,5,10] - try { - assert arr.lowerBound(4) == 1 - assert arr.lowerBound(5) == 1 - assert arr.lowerBound(6) == 2 - } except ValueError {} - # Tests for isSorted - var srt1 = [1,2,3,4,4,4,4,5] - var srt2 = ["iello","hello"] - var srt3 = [1.0,1.0,1.0] - var srt4: seq[int] = @[] - assert srt1.isSorted(cmp) == true - assert srt2.isSorted(cmp) == false - assert srt3.isSorted(cmp) == true - var srtseq = newSeq[int]() - assert srtseq.isSorted(cmp) == true - # Tests for reversed - var arr1 = @[0,1,2,3,4] - assert arr1.reversed() == @[4,3,2,1,0] - for i in 0 .. high(arr1) { - assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)] - assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i] - } -} From 88cf6573e04bd7ee8762aa336460b9748f0d4644 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 08:59:39 +0200 Subject: [PATCH 144/214] fixes #7743 --- compiler/cgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d838f9b9c3..693930fbc4 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -746,7 +746,7 @@ proc genProcAux(m: BModule, prc: PSym) = else: fillResult(resNode) assignParam(p, res) - resetLoc(p, res.loc) + if sfNoInit notin prc.flags: resetLoc(p, res.loc) if skipTypes(res.typ, abstractInst).kind == tyArray: #incl(res.loc.flags, lfIndirect) res.loc.storage = OnUnknown From 6e8d5790c838ecacf3a33bf3162db62b5cdc5304 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 09:00:41 +0200 Subject: [PATCH 145/214] pegs: fixes another null accessing bug --- lib/pure/pegs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 6355c4899c..8304298421 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -617,7 +617,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. a, b: Rune result = start while i < len(p.term): - while true: + while i < len(p.term): fastRuneAt(p.term, i, a) if a != Rune('_'): break while result < s.len: From 700a2e125becf058f1d9d571e2c30f60888e1c53 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 09:00:55 +0200 Subject: [PATCH 146/214] make the tester compile without warnings --- tests/testament/tester.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index f08c830790..0c6f376d30 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -212,18 +212,18 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarg elif expected.tfile == "" and extractFilename(expected.file) != extractFilename(given.file) and "internal error:" notin expected.msg: r.addResult(test, target, expected.file, given.file, reFilesDiffer) - elif expected.line != given.line and expected.line != 0 or + elif expected.line != given.line and expected.line != 0 or expected.column != given.column and expected.column != 0: r.addResult(test, target, $expected.line & ':' & $expected.column, - $given.line & ':' & $given.column, + $given.line & ':' & $given.column, reLinesDiffer) elif expected.tfile != "" and extractFilename(expected.tfile) != extractFilename(given.tfile) and "internal error:" notin expected.msg: r.addResult(test, target, expected.tfile, given.tfile, reFilesDiffer) - elif expected.tline != given.tline and expected.tline != 0 or + elif expected.tline != given.tline and expected.tline != 0 or expected.tcolumn != given.tcolumn and expected.tcolumn != 0: r.addResult(test, target, $expected.tline & ':' & $expected.tcolumn, - $given.tline & ':' & $given.tcolumn, + $given.tline & ':' & $given.tcolumn, reLinesDiffer) else: r.addResult(test, target, expected.msg, given.msg, reSuccess) From 97056fbb9bd75a6fcf33f8bd0cb9b88f075bbb51 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sun, 6 May 2018 15:34:22 +0700 Subject: [PATCH 147/214] fixes #7774 (#7783) --- compiler/vmgen.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index f7d3237b8d..7f91e63db9 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1554,7 +1554,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = of tyCString, tyString: result = newNodeIT(nkStrLit, info, t) result.strVal = "" - of tyVar, tyLent, tyPointer, tyPtr, tySequence, tyExpr, + of tyVar, tyLent, tyPointer, tyPtr, tyExpr, tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil: result = newNodeIT(nkNilLit, info, t) of tyProc: @@ -1585,6 +1585,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = result = newNodeIT(nkCurly, info, t) of tyOpt: result = newNodeIT(nkNilLit, info, t) + of tySequence: + result = newNodeIT(nkBracket, info, t) else: globalError(info, "cannot create null element for: " & $t.kind) From d8dd43e5003d407d105ee9b6f9f2c6f4f45902d8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 10:49:09 +0200 Subject: [PATCH 148/214] fixes #7757 --- compiler/destroyer.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index ffa3e37e55..cd16469de3 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -430,6 +430,7 @@ proc injectDestructorCalls*(owner: PSym; n: PNode): PNode = c.tmp.typ = c.tmpObj c.destroys = newNodeI(nkStmtList, n.info) c.topLevelVars = newNodeI(nkVarSection, n.info) + c.toDropBit = initTable[int, PSym]() let cfg = constructCfg(owner, n) shallowCopy(c.g, cfg) c.jumpTargets = initIntSet() From 26d89fa09c3a214c9c2107367c3d3fd76f7b8e1c Mon Sep 17 00:00:00 2001 From: alaviss Date: Sun, 6 May 2018 15:55:19 +0700 Subject: [PATCH 149/214] options: use isSome (#7782) Fixes #7780 --- lib/pure/options.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/options.nim b/lib/pure/options.nim index aaffb57caa..bd01b208ae 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -134,7 +134,7 @@ proc get*[T](self: Option[T]): T = proc get*[T](self: Option[T], otherwise: T): T = ## Returns the contents of this option or `otherwise` if the option is none. - if self.has: + if self.isSome: self.val else: otherwise @@ -154,7 +154,7 @@ proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] = proc flatten*[A](self: Option[Option[A]]): Option[A] = ## Remove one level of structure in a nested Option. - if self.has: + if self.isSome: self.val else: none(A) @@ -179,14 +179,14 @@ proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] = proc `==`*(a, b: Option): bool = ## Returns ``true`` if both ``Option``s are ``none``, ## or if they have equal values - (a.has and b.has and a.val == b.val) or (not a.has and not b.has) + (a.isSome and b.isSome and a.val == b.val) or (not a.isSome and not b.isSome) proc `$`*[T](self: Option[T]): string = ## Get the string representation of this option. If the option has a value, ## the result will be `Some(x)` where `x` is the string representation of the contained value. ## If the option does not have a value, the result will be `None[T]` where `T` is the name of ## the type contained in the option. - if self.has: + if self.isSome: "Some(" & $self.val & ")" else: "None[" & T.name & "]" From d3ad46702284ad248d2a27bb65812315168c4beb Mon Sep 17 00:00:00 2001 From: Florent Date: Sun, 6 May 2018 10:56:40 +0200 Subject: [PATCH 150/214] Fixes #7764 (#7767) * Fixes #7764 * Change KEY_RECORD_EVENT filter * Update terminal.nim * Revert changes and modify readPasswordFromStdIn --- lib/pure/terminal.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 002181a6f6..5249e23c2f 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -759,6 +759,10 @@ when defined(windows): x = runeLenAt(password.string, i) inc i, x password.string.setLen(max(password.len - x, 0)) + of chr(0x0): + # modifier key - ignore - for details see + # https://github.com/nim-lang/Nim/issues/7764 + continue else: password.string.add(toUTF8(c.Rune)) stdout.write "\n" From b13296533012426d386e986322009363af8a51bd Mon Sep 17 00:00:00 2001 From: Flaviu Tamas Date: Sun, 6 May 2018 05:23:08 -0400 Subject: [PATCH 151/214] Allow using CC environment variable with csources (#7754) --- tools/niminst/buildsh.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl index 3e7d8ae6ec..be6d437546 100644 --- a/tools/niminst/buildsh.tmpl +++ b/tools/niminst/buildsh.tmpl @@ -39,8 +39,8 @@ do esac done -CC="gcc" -LINKER="gcc" +CC="${CC:-gcc}" +LINKER="${LD:-gcc}" COMP_FLAGS="${CPPFLAGS:-} ${CFLAGS:-} ?{c.ccompiler.flags}$extraBuildArgs" LINK_FLAGS="${LDFLAGS:-} ?{c.linker.flags}" PS4="" From 79ec95a9b57a857b511fb049678778b6945a544b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 20:07:42 +0200 Subject: [PATCH 152/214] remove hardly used TimeMachine feature --- compiler/commands.nim | 3 +-- compiler/options.nim | 25 ------------------------- doc/koch.rst | 33 ++------------------------------- koch.nim | 1 - 4 files changed, 3 insertions(+), 59 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index d8d8ae4b71..204baaa16e 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -31,7 +31,6 @@ import # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") -bootSwitch(usedAvoidTimeMachine, noTimeMachine, "-d:avoidTimeMachine") bootSwitch(usedNativeStacktrace, defined(nativeStackTrace) and nativeStackTraceSupported, "-d:nativeStackTrace") @@ -106,7 +105,7 @@ proc writeVersionInfo(pass: TCmdLinePass) = when gitHash.len == 40: msgWriteln("git hash: " & gitHash, {msgStdout}) - msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine & + msgWriteln("active boot switches:" & usedRelease & usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas & usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC, {msgStdout}) diff --git a/compiler/options.nim b/compiler/options.nim index f8cb735ae6..fe8be5e0c4 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -17,7 +17,6 @@ const hasFFI* = defined(useFFI) newScopeForIf* = true useCaas* = not defined(noCaas) - noTimeMachine* = defined(avoidTimeMachine) and defined(macosx) copyrightYear* = "2018" type # please make sure we have under 32 options @@ -329,28 +328,6 @@ proc toGeneratedFile*(path, ext: string): string = result = joinPath([getNimcacheDir(), changeFileExt(tail, ext)]) #echo "toGeneratedFile(", path, ", ", ext, ") = ", result -when noTimeMachine: - var alreadyExcludedDirs = initSet[string]() - proc excludeDirFromTimeMachine(dir: string) {.raises: [].} = - ## Calls a macosx command on the directory to exclude it from backups. - ## - ## The macosx tmutil command is invoked to mark the specified path as an - ## item to be excluded from time machine backups. If a path already exists - ## with files before excluding it, newer files won't be added to the - ## directory, but previous files won't be removed from the backup until the - ## user deletes that directory. - ## - ## The whole proc is optional and will ignore all kinds of errors. The only - ## way to be sure that it works is to call ``tmutil isexcluded path``. - if alreadyExcludedDirs.contains(dir): return - alreadyExcludedDirs.incl(dir) - try: - var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir]) - discard p.waitForExit - p.close - except Exception: - discard - proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = var (head, tail) = splitPath(f) #if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep)) @@ -358,8 +335,6 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = if createSubDir: try: createDir(subdir) - when noTimeMachine: - excludeDirFromTimeMachine(subdir) except OSError: writeLine(stdout, "cannot create directory: " & subdir) quit(1) diff --git a/doc/koch.rst b/doc/koch.rst index ff62b8186d..35cf9d8b65 100644 --- a/doc/koch.rst +++ b/doc/koch.rst @@ -35,32 +35,8 @@ options: By default a debug version is created, passing this option will force a release build, which is much faster and should be preferred unless you are debugging the compiler. --d:useGnuReadline - Includes the `rdstdin module `_ for `interactive - mode `_ (aka ``nim i``). - This is not needed on Windows. On other platforms this may - incorporate the GNU readline library. --d:nativeStacktrace - Use native stack traces (only for Mac OS X or Linux). --d:avoidTimeMachine - Only for Mac OS X, activating this switch will force excluding - the generated ``nimcache`` directories from Time Machine backups. - By default ``nimcache`` directories will be included in backups, - and just for the Nim compiler itself it means backing up 20MB - of generated files each time you update the compiler. Using this - option will make the compiler invoke the `tmutil - `_ - command on all ``nimcache`` directories, setting their backup - exclusion bit. - - You can use the following command to locate all ``nimcache`` - directories and check their backup exclusion bit:: - - $ find . -type d -name nimcache -exec tmutil isexcluded \{\} \; ---gc:refc|v2|markAndSweep|boehm|go|none - Selects which garbage collection strategy to use for the compiler - and generated code. See the `Nim's Garbage Collector `_ - documentation for more information. +-d:useLinenoise + Use the linenoise library for interactive mode (not needed on Windows). After compilation is finished you will hopefully end up with the nim compiler in the ``bin`` directory. You can add Nim's ``bin`` directory to @@ -104,8 +80,3 @@ be rerun in serial fashion so that meaninful error output can be gathered for inspection. The ``--parallelBuild:n`` switch or configuration option can be used to force a specific number of parallel jobs or run everything serially from the start (``n == 1``). - -zip command ------------ - -The `zip`:idx: command builds the installation ZIP package. diff --git a/koch.nim b/koch.nim index 7a75ebf714..4f85c6583b 100644 --- a/koch.nim +++ b/koch.nim @@ -47,7 +47,6 @@ Boot options: -d:release produce a release version of the compiler -d:useLinenoise use the linenoise library for interactive mode (not needed on Windows) - -d:avoidTimeMachine only for Mac OS X, excludes nimcache dir from backups Commands for core developers: web [options] generates the website and the full documentation From 7897026e575a4abd44583cd453b8d36cac96327e Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 7 May 2018 12:30:13 +0700 Subject: [PATCH 153/214] pretty, prettybase: simplify relative paths (#7779) This allows nimble to be built with compiler as a nimble package --- compiler/nimfix/pretty.nim | 2 +- compiler/nimfix/prettybase.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim index 4627264dc4..7af2a86dce 100644 --- a/compiler/nimfix/pretty.nim +++ b/compiler/nimfix/pretty.nim @@ -13,7 +13,7 @@ import strutils, os, intsets, strtabs -import "../compiler" / [options, ast, astalgo, msgs, semdata, ropes, idents] +import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents] import prettybase type diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim index ecb4b00931..c32dbe623f 100644 --- a/compiler/nimfix/prettybase.nim +++ b/compiler/nimfix/prettybase.nim @@ -8,7 +8,7 @@ # import strutils, lexbase, streams -import "../compiler" / [ast, msgs, idents] +import ".." / [ast, msgs, idents] from os import splitFile type From bdcb72959729a5c4b195f9bf6b2ac8783c27f38e Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 18 Apr 2018 19:40:08 +0300 Subject: [PATCH 154/214] Better support for treating templates and macros as symbols. This allows you to pass a template or a macro to another macro which can then inspect the implementation of the former template/macro using `getImpl`. Since templates can be freely redefined, this allows you to treat their symbols as compile-time variables that have lexical scope. A motivating PoC example for a logging library taking advantage of this will be provided in the next commit. Implementation details: * The name of a template or a macro will be consider a symbol if the template/macro requires parameters * For parameterless templates/macros, you can use `bindSym`, which was extended to also work outside of compile-time procs. --- compiler/ast.nim | 13 +++ compiler/evaltempl.nim | 2 +- compiler/semexprs.nim | 8 +- compiler/semmagic.nim | 4 + compiler/sigmatch.nim | 8 +- lib/core/macros.nim | 2 +- tests/macros/ttemplatesymbols.nim | 173 ++++++++++++++++++++++++++++++ 7 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 tests/macros/ttemplatesymbols.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index b8202abe60..350fa5f6ac 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1615,6 +1615,19 @@ proc originatingModule*(s: PSym): PSym = proc isRoutine*(s: PSym): bool {.inline.} = result = s.kind in skProcKinds +proc isCompileTimeProc*(s: PSym): bool {.inline.} = + result = s.kind == skMacro or + s.kind == skProc and sfCompileTime in s.flags + +proc requiredParams*(s: PSym): int = + # Returns the number of required params (without default values) + # XXX: Perhaps we can store this in the `offset` field of the + # symbol instead? + for i in 1 ..< s.typ.len: + if s.typ.n[i].sym.ast != nil: + return i - 1 + return s.typ.len - 1 + proc hasPattern*(s: PSym): bool {.inline.} = result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index fbb7eb2e6e..5024308157 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -63,7 +63,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = # if the template has zero arguments, it can be called without ``()`` # `n` is then a nkSym or something similar var totalParams = case n.kind - of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: n.len-1 + of nkCallKinds: n.len-1 else: 0 var diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 4a3672aa0d..29f377a190 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -960,18 +960,20 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = else: result = newSymNode(s, n.info) of skMacro: - if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0: + if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or + (n.kind notin nkCallKinds and s.requiredParams > 0): markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) - result = newSymNode(s, n.info) + result = symChoice(c, n, s, scClosed) else: result = semMacroExpr(c, n, n, s, flags) of skTemplate: if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or + (n.kind notin nkCallKinds and s.requiredParams > 0) or sfCustomPragma in sym.flags: markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) - result = newSymNode(s, n.info) + result = symChoice(c, n, s, scClosed) else: result = semTemplateExpr(c, n, s, flags) of skParam: diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 3f0df00650..bf3c55120f 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -199,6 +199,10 @@ proc semBindSym(c: PContext, n: PNode): PNode = if s != nil: # we need to mark all symbols: var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal)) + if not getCurrOwner(c).isCompileTimeProc: + # inside regular code, bindSym resolves to the sym-choice + # nodes (see tinspectsymbol) + return sc result.add(sc) else: errorUndeclaredIdentifier(c, n.sons[1].info, sl.strVal) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4263ef5813..7e566afad6 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2032,8 +2032,9 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, y.calleeSym = m.calleeSym z.calleeSym = m.calleeSym var best = -1 - for i in countup(0, sonsLen(arg) - 1): - if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter, skIterator}: + for i in 0 ..< arg.len: + if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter, + skIterator, skMacro, skTemplate}: copyCandidate(z, m) z.callee = arg.sons[i].typ if tfUnresolved in z.callee.flags: continue @@ -2062,6 +2063,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, x = z elif cmp == 0: y = z # z is as good as x + if x.state == csEmpty: result = nil elif y.state == csMatch and cmpCandidates(x, y) == 0: @@ -2070,7 +2072,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, # ambiguous: more than one symbol fits! # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match # anyway: - if f.kind == tyExpr: result = arg + if f.kind in {tyExpr, tyStmt}: result = arg else: result = nil else: # only one valid interpretation found: diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 1dc067e1ac..fa5cd67dfb 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -385,7 +385,7 @@ type {.deprecated: [TBindSymRule: BindSymRule].} -proc bindSym*(ident: string, rule: BindSymRule = brClosed): NimNode {. +proc bindSym*(ident: static[string], rule: BindSymRule = brClosed): NimNode {. magic: "NBindSym", noSideEffect.} ## creates a node that binds `ident` to a symbol node. The bound symbol ## may be an overloaded symbol. diff --git a/tests/macros/ttemplatesymbols.nim b/tests/macros/ttemplatesymbols.nim new file mode 100644 index 0000000000..8d9c9ec025 --- /dev/null +++ b/tests/macros/ttemplatesymbols.nim @@ -0,0 +1,173 @@ +import + macros, algorithm, strutils + +proc normalProc(x: int) = + echo x + +template templateWithtouParams = + echo 10 + +proc overloadedProc(x: int) = + echo x + +proc overloadedProc(x: string) = + echo x + +proc overloadedProc[T](x: T) = + echo x + +template normalTemplate(x: int) = + echo x + +template overloadedTemplate(x: int) = + echo x + +template overloadedTemplate(x: string) = + echo x + +macro normalMacro(x: int): untyped = + discard + +macro macroWithoutParams: untyped = + discard + +macro inspectSymbol(sym: typed, expected: static[string]): untyped = + if sym.kind == nnkSym: + echo "Symbol node:" + let res = sym.getImpl.repr & "\n" + echo res + # echo "|", res, "|" + # echo "|", expected, "|" + if expected.len > 0: assert res == expected + elif sym.kind in {nnkClosedSymChoice, nnkOpenSymChoice}: + echo "Begin sym choice:" + var results = newSeq[string](0) + for innerSym in sym: + results.add innerSym.getImpl.repr + sort(results, cmp[string]) + let res = results.join("\n") & "\n" + echo res + if expected.len > 0: assert res == expected + echo "End symchoice." + else: + echo "Non-symbol node: ", sym.kind + if expected.len > 0: assert $sym.kind == expected + +macro inspectUntyped(sym: untyped, expected: static[string]): untyped = + let res = sym.repr + echo "Untyped node: ", res + assert res == expected + +inspectSymbol templateWithtouParams, "nnkCommand" + # this template is expanded, because bindSym was not used + # the end result is the template body (nnkCommand) + +inspectSymbol bindSym("templateWithtouParams"), """ +template templateWithtouParams() = + echo 10 + +""" + +inspectSymbol macroWithoutParams, "nnkEmpty" + # Just like the template above, the macro was expanded + +inspectSymbol bindSym("macroWithoutParams"), """ +macro macroWithoutParams(): untyped = + discard + +""" + +inspectSymbol normalMacro, """ +macro normalMacro(x: int): untyped = + discard + +""" + # Since the normalMacro has params, it's automatically + # treated as a symbol here (no need for `bindSym`) + +inspectSymbol bindSym("normalMacro"), """ +macro normalMacro(x: int): untyped = + discard + +""" + +inspectSymbol normalTemplate, """ +template normalTemplate(x: int) = + echo x + +""" + +inspectSymbol bindSym("normalTemplate"), """ +template normalTemplate(x: int) = + echo x + +""" + +inspectSymbol overloadedTemplate, """ +template overloadedTemplate(x: int) = + echo x + +template overloadedTemplate(x: string) = + echo x + +""" + +inspectSymbol bindSym("overloadedTemplate"), """ +template overloadedTemplate(x: int) = + echo x + +template overloadedTemplate(x: string) = + echo x + +""" + +inspectUntyped bindSym("overloadedTemplate"), """bindSym("overloadedTemplate")""" + # binSym is active only in the presense of `typed` params. + # `untyped` params still get the raw AST + +inspectSymbol normalProc, """ +proc normalProc(x: int) = + echo [x] + +""" + +inspectSymbol bindSym("normalProc"), """ +proc normalProc(x: int) = + echo [x] + +""" + +inspectSymbol overloadedProc, """ +proc overloadedProc(x: int) = + echo [x] + +proc overloadedProc(x: string) = + echo [x] + +proc overloadedProc[T](x: T) = + echo x + +""" + # XXX: There seems to be a repr rendering problem above. + # Notice that `echo [x]` + +inspectSymbol overloadedProc[float], """ +proc overloadedProc(x: T) = + echo [x] + +""" + # As expected, when we select a specific generic, the + # AST is no longer a symChoice + +inspectSymbol bindSym("overloadedProc"), """ +proc overloadedProc(x: int) = + echo [x] + +proc overloadedProc(x: string) = + echo [x] + +proc overloadedProc[T](x: T) = + echo x + +""" + From 2b8bf8fc4ae4204089a9f177c4ba62c5872d4f0a Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 19 Apr 2018 19:16:05 +0300 Subject: [PATCH 155/214] A motivating example for the new `bindSym` behavior. The example is a proof-of-concept logging library, allowing you to define lexically-scoped environments where certain logging attributes are applied automatically to all logging statements. fixes tmacro1 (use of `bindSym` inside static blocks) --- compiler/semdata.nim | 1 + compiler/semexprs.nim | 2 + compiler/semmagic.nim | 2 +- compiler/semstmts.nim | 2 + tests/macros/tstructuredlogging.nim | 154 ++++++++++++++++++++++++++++ 5 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 tests/macros/tstructuredlogging.nim diff --git a/compiler/semdata.nim b/compiler/semdata.nim index fc0488814c..62be471f75 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -89,6 +89,7 @@ type ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot # store this info in the syms themselves!) inGenericContext*: int # > 0 if we are in a generic type + inStaticContext*: int # > 0 if we are inside a static: block inUnrolledContext*: int # > 0 if we are unrolling a loop compilesContextId*: int # > 0 if we are in a ``compiles`` magic compilesContextIdGenerator*: int diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 29f377a190..5ef9916adf 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1780,6 +1780,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = let oldInGenericContext = c.inGenericContext let oldInUnrolledContext = c.inUnrolledContext let oldInGenericInst = c.inGenericInst + let oldInStaticContext = c.inStaticContext let oldProcCon = c.p c.generics = @[] var err: string @@ -1794,6 +1795,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = c.inGenericContext = oldInGenericContext c.inUnrolledContext = oldInUnrolledContext c.inGenericInst = oldInGenericInst + c.inStaticContext = oldInStaticContext c.p = oldProcCon msgs.setInfoContextLen(oldContextLen) setLen(c.graph.owners, oldOwnerLen) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index bf3c55120f..e6e29b4d35 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -199,7 +199,7 @@ proc semBindSym(c: PContext, n: PNode): PNode = if s != nil: # we need to mark all symbols: var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal)) - if not getCurrOwner(c).isCompileTimeProc: + if not (c.inStaticContext > 0 or getCurrOwner(c).isCompileTimeProc): # inside regular code, bindSym resolves to the sym-choice # nodes (see tinspectsymbol) return sc diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b0bd4e0f61..f3cf4196f2 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1754,7 +1754,9 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode = proc semStaticStmt(c: PContext, n: PNode): PNode = #echo "semStaticStmt" #writeStackTrace() + inc c.inStaticContext let a = semStmt(c, n.sons[0]) + dec c.inStaticContext n.sons[0] = a evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner) result = newNodeI(nkDiscardStmt, n.info, 1) diff --git a/tests/macros/tstructuredlogging.nim b/tests/macros/tstructuredlogging.nim new file mode 100644 index 0000000000..05bb52a402 --- /dev/null +++ b/tests/macros/tstructuredlogging.nim @@ -0,0 +1,154 @@ +discard """ +output: ''' +main started: a=10, b=inner-b, c=10, d=some-d, x=16, z=20 +exiting: a=12, b=overriden-b, c=100, msg=bye bye, x=16 +''' +""" + +import macros, tables + +template scopeHolder = + 0 # scope revision number + +type + BindingsSet = Table[string, NimNode] + +proc actualBody(n: NimNode): NimNode = + # skip over the double StmtList node introduced in `mergeScopes` + result = n.body + if result.kind == nnkStmtList and result[0].kind == nnkStmtList: + result = result[0] + +iterator bindings(n: NimNode, skip = 0): (string, NimNode) = + for i in skip ..< n.len: + let child = n[i] + if child.kind in {nnkAsgn, nnkExprEqExpr}: + let name = $child[0] + let value = child[1] + yield (name, value) + +proc scopeRevision(scopeHolder: NimNode): int = + # get the revision number from a scopeHolder sym + assert scopeHolder.kind == nnkSym + var revisionNode = scopeHolder.getImpl.actualBody[0] + result = int(revisionNode.intVal) + +proc lastScopeHolder(scopeHolders: NimNode): NimNode = + # get the most recent scopeHolder from a symChoice node + if scopeHolders.kind in {nnkClosedSymChoice, nnkOpenSymChoice}: + var bestScopeRev = 0 + assert scopeHolders.len > 0 + for scope in scopeHolders: + let rev = scope.scopeRevision + if result == nil or rev > bestScopeRev: + result = scope + bestScopeRev = rev + else: + result = scopeHolders + + assert result.kind == nnkSym + +macro mergeScopes(scopeHolders: typed, newBindings: untyped): untyped = + var + bestScope = scopeHolders.lastScopeHolder + bestScopeRev = bestScope.scopeRevision + + var finalBindings = initTable[string, NimNode]() + for k, v in bindings(bestScope.getImpl.actualBody, skip = 1): + finalBindings[k] = v + + for k, v in bindings(newBindings): + finalBindings[k] = v + + var newScopeDefinition = newStmtList(newLit(bestScopeRev + 1)) + + for k, v in finalBindings: + newScopeDefinition.add newAssignment(newIdentNode(k), v) + + result = quote: + template scopeHolder = `newScopeDefinition` + +template scope(newBindings: untyped) {.dirty.} = + mergeScopes(bindSym"scopeHolder", newBindings) + +type + TextLogRecord = object + line: string + + StdoutLogRecord = object + +template setProperty(r: var TextLogRecord, key: string, val: string, isFirst: bool) = + if not first: r.line.add ", " + r.line.add key + r.line.add "=" + r.line.add val + +template setEventName(r: var StdoutLogRecord, name: string) = + stdout.write(name & ": ") + +template setProperty(r: var StdoutLogRecord, key: string, val: auto, isFirst: bool) = + when not isFirst: stdout.write ", " + stdout.write key + stdout.write "=" + stdout.write $val + +template flushRecord(r: var StdoutLogRecord) = + stdout.write "\n" + stdout.flushFile + +macro logImpl(scopeHolders: typed, + logStmtProps: varargs[untyped]): untyped = + let lexicalScope = scopeHolders.lastScopeHolder.getImpl.actualBody + var finalBindings = initOrderedTable[string, NimNode]() + + for k, v in bindings(lexicalScope, skip = 1): + finalBindings[k] = v + + for k, v in bindings(logStmtProps, skip = 1): + finalBindings[k] = v + + finalBindings.sort(system.cmp) + + let eventName = logStmtProps[0] + assert eventName.kind in {nnkStrLit} + let record = genSym(nskVar, "record") + + result = quote: + var `record`: StdoutLogRecord + setEventName(`record`, `eventName`) + + var isFirst = true + for k, v in finalBindings: + result.add newCall(newIdentNode"setProperty", + record, newLit(k), v, newLit(isFirst)) + isFirst = false + + result.add newCall(newIdentNode"flushRecord", record) + +template log(props: varargs[untyped]) {.dirty.} = + logImpl(bindSym"scopeHolder", props) + +scope: + a = 12 + b = "original-b" + +scope: + x = 16 + b = "overriden-b" + +scope: + c = 100 + +proc main = + scope: + c = 10 + + scope: + z = 20 + + log("main started", a = 10, b = "inner-b", d = "some-d") + +main() + +log("exiting", msg = "bye bye") + From e678a4285df6e567c5e924bfae941ae6b312790d Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Apr 2018 12:50:54 +0300 Subject: [PATCH 156/214] Bugfix: Allow matching on nkExprEqExpr against varargs[untyped] This enables macros accepting arbitrary keyword arguments: log("foo", prop1 = "bar", prop2 = "baz") As an added bonus, simple templates with varargs arguments can now forward their params to procs accepting keyword arguments. --- compiler/sigmatch.nim | 3 ++- tests/overload/tparam_forwarding.nim | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7e566afad6..716a4f54ab 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2173,7 +2173,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode, var formal: PSym = if formalLen > 1: m.callee.n.sons[1].sym else: nil while a < n.len: - if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped: + if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped: + formal = m.callee.n.sons[f].sym incl(marker, formal.position) if container.isNil: container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info)) diff --git a/tests/overload/tparam_forwarding.nim b/tests/overload/tparam_forwarding.nim index c1b276bfc9..cd3de32e37 100644 --- a/tests/overload/tparam_forwarding.nim +++ b/tests/overload/tparam_forwarding.nim @@ -6,6 +6,10 @@ output: '''baz a b c +x: 1, y: test 1 +x: 2, y: test 2 +x: 10, y: test 3 +x: 4, y: test 4 ''' """ @@ -35,3 +39,14 @@ templateForwarding fooVarargs, "test".len > 3, Foo(x: 10), Foo(x: 100), Foo(x: 1 procForwarding "a", "b", "c" +proc hasKeywordArgs(x = 10, y = "y") = + echo "x: ", x, ", y: ", y + +proc hasRegularArgs(x: int, y: string) = + echo "x: ", x, ", y: ", y + +templateForwarding(hasRegularArgs, true, 1, "test 1") +templateForwarding(hasKeywordArgs, true, 2, "test 2") +templateForwarding(hasKeywordArgs, true, y = "test 3") +templateForwarding(hasKeywordArgs, true, y = "test 4", x = 4) + From b0d85b0adf950685e2f7d88665a3d5b03cd06cfd Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Apr 2018 13:30:08 +0300 Subject: [PATCH 157/214] Backwards-compatible support for keyword arguments in the command syntax --- changelog.md | 2 ++ compiler/parser.nim | 17 +++++++++++++---- tests/overload/tparam_forwarding.nim | 7 ++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 9af2aae83a..fe935106a1 100644 --- a/changelog.md +++ b/changelog.md @@ -95,11 +95,13 @@ - ``nil`` for strings/seqs is finally gone. Instead the default value for these is ``"" / @[]``. + - Accessing the binary zero terminator in Nim's native strings is now invalid. Internally a Nim string still has the trailing zero for zero-copy interoperability with ``cstring``. Compile your code with the new switch ``--laxStrings:on`` if you need a transition period. +- The command syntax now supports keyword arguments after the first comma. ### Tool changes diff --git a/compiler/parser.nim b/compiler/parser.nim index 14683e3074..0a3815f132 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -702,10 +702,17 @@ proc namedParams(p: var TParser, callee: PNode, # progress guaranteed exprColonEqExprListAux(p, endTok, result) -proc commandParam(p: var TParser): PNode = +proc commandParam(p: var TParser, isFirstParam: var bool): PNode = result = parseExpr(p) if p.tok.tokType == tkDo: result = postExprBlocks(p, result) + elif p.tok.tokType == tkEquals and not isFirstParam: + let lhs = result + result = newNodeP(nkExprEqExpr, p) + getTok(p) + addSon(result, lhs) + addSon(result, parseExpr(p)) + isFirstParam = false proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks? @@ -748,10 +755,11 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = let a = result result = newNodeP(nkCommand, p) addSon(result, a) + var isFirstParam = true when true: # progress NOT guaranteed p.hasProgress = false - addSon result, commandParam(p) + addSon result, commandParam(p, isFirstParam) if not p.hasProgress: break else: while p.tok.tokType != tkEof: @@ -1303,17 +1311,18 @@ proc parseExprStmt(p: var TParser): PNode = addSon(result, b) else: # simpleExpr parsed 'p a' from 'p a, b'? + var isFirstParam = false if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand: result = a while true: getTok(p) optInd(p, result) - addSon(result, commandParam(p)) + addSon(result, commandParam(p, isFirstParam)) if p.tok.tokType != tkComma: break elif p.tok.indent < 0 and isExprStart(p): result = newNode(nkCommand, a.info, @[a]) while true: - addSon(result, commandParam(p)) + addSon(result, commandParam(p, isFirstParam)) if p.tok.tokType != tkComma: break getTok(p) optInd(p, result) diff --git a/tests/overload/tparam_forwarding.nim b/tests/overload/tparam_forwarding.nim index cd3de32e37..b0eea42c71 100644 --- a/tests/overload/tparam_forwarding.nim +++ b/tests/overload/tparam_forwarding.nim @@ -46,7 +46,8 @@ proc hasRegularArgs(x: int, y: string) = echo "x: ", x, ", y: ", y templateForwarding(hasRegularArgs, true, 1, "test 1") -templateForwarding(hasKeywordArgs, true, 2, "test 2") -templateForwarding(hasKeywordArgs, true, y = "test 3") -templateForwarding(hasKeywordArgs, true, y = "test 4", x = 4) +templateForwarding hasKeywordArgs, true, 2, "test 2" + +templateForwarding(hasKeywordArgs, true, y = "test 3") +templateForwarding hasKeywordArgs, true, y = "test 4", x = 4 From ae5c946a325c8833472173e63017dbed39f23abe Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Apr 2018 13:50:21 +0300 Subject: [PATCH 158/214] Support thread-local variables declared inside procs; fixes #7565 --- changelog.md | 3 ++ compiler/pragmas.nim | 2 +- doc/manual.rst | 5 ++- tests/threads/tthreadvars.nim | 78 +++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 tests/threads/tthreadvars.nim diff --git a/changelog.md b/changelog.md index fe935106a1..4f87d5fe16 100644 --- a/changelog.md +++ b/changelog.md @@ -103,6 +103,9 @@ - The command syntax now supports keyword arguments after the first comma. +- Thread-local variables can now be declared inside procs. This implies all + the effects of the `global` pragma. + ### Tool changes - ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 5aa9037719..0b8bcd374b 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -777,7 +777,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, incl(sym.flags, sfRegister) of wThreadVar: noVal(it) - incl(sym.flags, sfThread) + incl(sym.flags, {sfThread, sfGlobal}) of wDeadCodeElimUnused: discard # deprecated, dead code elim always on of wNoForward: pragmaNoForward(c, it) of wReorder: pragmaNoForward(c, it, sfReorder) diff --git a/doc/manual.rst b/doc/manual.rst index fabcf058ad..1a4ed19b7b 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7798,8 +7798,9 @@ Future directions: Threadvar pragma ---------------- -A global variable can be marked with the ``threadvar`` pragma; it is -a `thread-local`:idx: variable then: +A variable can be marked with the ``threadvar`` pragma, which makes it a +`thread-local`:idx: variable; Additionally, this implies all the effects +of the ``global`` pragma. .. code-block:: nim var checkpoints* {.threadvar.}: seq[string] diff --git a/tests/threads/tthreadvars.nim b/tests/threads/tthreadvars.nim new file mode 100644 index 0000000000..81aa2e5ecf --- /dev/null +++ b/tests/threads/tthreadvars.nim @@ -0,0 +1,78 @@ +discard """ +output: ''' +10 +1111 +1222 +3030303 +3060606 +6060606 +6121212 +3030903 +3061206 +3031503 +3061806 +5050505 +5101010 +''' +""" + +import typetraits + +var tls1 {.threadvar.}: int +var g0: int +var g1 {.global.}: int + +proc customInc(x: var int, delta: int) = + x += delta + +customInc(tls1, 10) +echo tls1 + +proc nonGenericProc: int = + var local: int + var nonGenericTls {.threadvar.}: int + var nonGenericGlobal {.global.}: int + var nonGenericMixedPragmas {.global, threadvar.}: int + + customInc local, 1000 + customInc nonGenericTls, 1 + customInc nonGenericGlobal, 10 + customInc nonGenericMixedPragmas, 100 + + return local + nonGenericTls + nonGenericGlobal + nonGenericMixedPragmas + +proc genericProc(T: typedesc): int = + var local: int + var genericTls {.threadvar.}: int + var genericGlobal {.global.}: int + var genericMixedPragmas {.global, threadvar.}: int + + customInc local, T.name.len * 1000000 + customInc genericTls, T.name.len * 1 + customInc genericGlobal, T.name.len * 100 + customInc genericMixedPragmas, T.name.len * 10000 + + return local + genericTls + genericGlobal + genericMixedPragmas + +echo nonGenericProc() +echo nonGenericProc() + +echo genericProc(int) +echo genericProc(int) + +echo genericProc(string) +echo genericProc(string) + +proc echoInThread[T]() {.thread.} = + echo genericProc(T) + echo genericProc(T) + +proc newEchoThread(T: typedesc) = + var t: Thread[void] + createThread(t, echoInThread[T]) + joinThreads(t) + +newEchoThread int +newEchoThread int +newEchoThread float + From 4409c82228ed2aa6d169c3b3dfbcbff914fc9af6 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Apr 2018 13:56:04 +0300 Subject: [PATCH 159/214] The `terminal` module now exports additional procs for generating ANSI color codes as strings. --- changelog.md | 2 ++ lib/pure/terminal.nim | 64 +++++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/changelog.md b/changelog.md index 4f87d5fe16..2a1e805739 100644 --- a/changelog.md +++ b/changelog.md @@ -72,6 +72,8 @@ - ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is now joined in ``binarySearch``. ``smartbinarySearch`` is now deprecated. +- The `terminal` module now exports additional procs for generating ANSI color + codes as strings. ### Language additions diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 5249e23c2f..db16c23b30 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -29,9 +29,7 @@ when not hasThreadSupport: var colorsFGCache = initTable[Color, string]() colorsBGCache = initTable[Color, string]() - when not defined(windows): - var - styleCache = initTable[int, string]() + styleCache = initTable[int, string]() var trueColorIsSupported: bool @@ -41,6 +39,7 @@ var const fgPrefix = "\x1b[38;2;" bgPrefix = "\x1b[48;2;" + ansiResetCode* = "\e[0m" when not defined(windows): const @@ -468,7 +467,7 @@ proc resetAttributes*(f: File) = else: discard setConsoleTextAttribute(hStdout, oldStdoutAttr) else: - f.write("\e[0m") + f.write(ansiResetCode) type Style* = enum ## different styles for text output @@ -487,15 +486,22 @@ when not defined(windows): gFG {.threadvar.}: int gBG {.threadvar.}: int - proc getStyleStr(style: int): string = - when hasThreadSupport: - result = fmt"{stylePrefix}{style}m" +proc ansiStyleCode*(style: int): string = + when hasThreadSupport: + result = fmt"{stylePrefix}{style}m" + else: + if styleCache.hasKey(style): + result = styleCache[style] else: - if styleCache.hasKey(style): - result = styleCache[style] - else: - result = fmt"{stylePrefix}{style}m" - styleCache[style] = result + result = fmt"{stylePrefix}{style}m" + styleCache[style] = result + +template ansiStyleCode*(style: Style): string = + ansiStyleCode(style.int) + +# The styleCache can be skipped when `style` is known at compile-time +template ansiStyleCode*(style: static[Style]): string = + (static(stylePrefix & $style.int & "m")) proc setStyle*(f: File, style: set[Style]) = ## Sets the terminal style. @@ -510,7 +516,7 @@ proc setStyle*(f: File, style: set[Style]) = discard setConsoleTextAttribute(h, old or a) else: for s in items(style): - f.write(getStyleStr(ord(s))) + f.write(ansiStyleCode(s)) proc writeStyled*(txt: string, style: set[Style] = {styleBright}) = ## Writes the text `txt` in a given `style` to stdout. @@ -524,9 +530,9 @@ proc writeStyled*(txt: string, style: set[Style] = {styleBright}) = stdout.write(txt) stdout.resetAttributes() if gFG != 0: - stdout.write(getStyleStr(gFG)) + stdout.write(ansiStyleCode(gFG)) if gBG != 0: - stdout.write(getStyleStr(gBG)) + stdout.write(ansiStyleCode(gBG)) type ForegroundColor* = enum ## terminal's foreground colors @@ -572,7 +578,7 @@ proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) = else: gFG = ord(fg) if bright: inc(gFG, 60) - f.write(getStyleStr(gFG)) + f.write(ansiStyleCode(gFG)) proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) = ## Sets the terminal's background color. @@ -594,10 +600,18 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) = else: gBG = ord(bg) if bright: inc(gBG, 60) - f.write(getStyleStr(gBG)) + f.write(ansiStyleCode(gBG)) +proc ansiForegroundColorCode*(fg: ForegroundColor, bright=false): string = + var style = ord(fg) + if bright: inc(style, 60) + return ansiStyleCode(style) -proc getFGColorStr(color: Color): string = +template ansiForegroundColorCode*(fg: static[ForegroundColor], + bright: static[bool] = false): string = + ansiStyleCode(fg.int + bright.int * 60) + +proc ansiForegroundColorCode*(color: Color): string = when hasThreadSupport: let rgb = extractRGB(color) result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m" @@ -609,7 +623,11 @@ proc getFGColorStr(color: Color): string = result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m" colorsFGCache[color] = result -proc getBGColorStr(color: Color): string = +template ansiForegroundColorCode*(color: static[Color]): string = + let rgb = extractRGB(color) + (static(fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m")) + +proc ansiBackgroundColorCode*(color: Color): string = when hasThreadSupport: let rgb = extractRGB(color) result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m" @@ -621,15 +639,19 @@ proc getBGColorStr(color: Color): string = result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m" colorsFGCache[color] = result +template ansiBackgroundColorCode*(color: static[Color]): string = + const rgb = extractRGB(color) + (static(fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m")) + proc setForegroundColor*(f: File, color: Color) = ## Sets the terminal's foreground true color. if trueColorIsEnabled: - f.write(getFGColorStr(color)) + f.write(ansiForegroundColorCode(color)) proc setBackgroundColor*(f: File, color: Color) = ## Sets the terminal's background true color. if trueColorIsEnabled: - f.write(getBGColorStr(color)) + f.write(ansiBackgroundColorCode(color)) proc setTrueColor(f: File, color: Color) = if fgSetColor: From 4ab1cfb0b07b33015652e8f0d0444f1feed18a57 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 3 May 2018 11:42:15 +0300 Subject: [PATCH 160/214] fix a compiler crash related to the new strings in C++ mode --- compiler/ast.nim | 2 +- compiler/astalgo.nim | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 350fa5f6ac..2cace380d9 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1684,7 +1684,7 @@ proc isException*(t: PType): bool = var base = t while base != nil: - if base.sym.magic == mException: + if base.sym != nil and base.sym.magic == mException: return true base = base.lastSon return false diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 196ac86903..a35fa4fbb9 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -69,22 +69,22 @@ proc debug*(n: PNode) {.deprecated.} template mdbg*: bool {.dirty.} = when compiles(c.module): - c.module.fileIdx == gProjectMainIdx + c.module.fileIdx.int32 == gProjectMainIdx elif compiles(c.c.module): - c.c.module.fileIdx == gProjectMainIdx + c.c.module.fileIdx.int32 == gProjectMainIdx elif compiles(m.c.module): - m.c.module.fileIdx == gProjectMainIdx + m.c.module.fileIdx.int32 == gProjectMainIdx elif compiles(cl.c.module): - cl.c.module.fileIdx == gProjectMainIdx + cl.c.module.fileIdx.int32 == gProjectMainIdx elif compiles(p): when compiles(p.lex): - p.lex.fileIdx == gProjectMainIdx + p.lex.fileIdx.int32 == gProjectMainIdx else: - p.module.module.fileIdx == gProjectMainIdx + p.module.module.fileIdx.int32 == gProjectMainIdx elif compiles(m.module.fileIdx): - m.module.fileIdx == gProjectMainIdx + m.module.fileIdx.int32 == gProjectMainIdx elif compiles(L.fileIdx): - L.fileIdx == gProjectMainIdx + L.fileIdx.int32 == gProjectMainIdx else: error() From 72976139009b9ae74669dc2443474f091c99f2e4 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 3 May 2018 19:42:20 +0300 Subject: [PATCH 161/214] Bugfix: The compiler were not inserting proper downcasts for generic types This resulted in a codegen error in C++ mode, because the generic types were not defined in modules where calls requiring downcasts were used (generating a downcast forces the inclusion of the full definition of the involved types). --- compiler/sigmatch.nim | 3 ++- compiler/types.nim | 4 ++-- tests/generics/module_with_generics.nim | 14 ++++++++++++++ tests/generics/t5602_inheritence.nim | 8 +++++++- 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/generics/module_with_generics.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 716a4f54ab..55d83d9908 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1962,7 +1962,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, inc(m.genericMatches) if arg.typ == nil: result = arg - elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple: + elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or + m.inheritancePenalty > 0: result = implicitConv(nkHiddenSubConv, f, arg, m, c) elif arg.typ.isEmptyContainer: result = arg.copyTree diff --git a/compiler/types.nim b/compiler/types.nim index edf4e5b46b..b9b6ab33cc 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -612,7 +612,7 @@ proc firstOrd*(t: PType): BiggestInt = else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position - of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic: + of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred: result = firstOrd(lastSon(t)) of tyOrdinal: if t.len > 0: result = firstOrd(lastSon(t)) @@ -651,7 +651,7 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt = of tyEnum: assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) result = t.n.sons[sonsLen(t.n) - 1].sym.position - of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic: + of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred: result = lastOrd(lastSon(t)) of tyProxy: result = 0 of tyOrdinal: diff --git a/tests/generics/module_with_generics.nim b/tests/generics/module_with_generics.nim new file mode 100644 index 0000000000..e801a4790e --- /dev/null +++ b/tests/generics/module_with_generics.nim @@ -0,0 +1,14 @@ +type + Base[T] = ref object {.inheritable.} + value*: T + + Derived[T] = ref object of Base[T] + derivedValue*: T + +proc makeDerived*[T](v: T): Derived[T] = + new result + result.value = v + +proc setBaseValue*[T](a: Base[T], value: T) = + a.value = value + diff --git a/tests/generics/t5602_inheritence.nim b/tests/generics/t5602_inheritence.nim index 6d48c796e6..ee5ba89d50 100644 --- a/tests/generics/t5602_inheritence.nim +++ b/tests/generics/t5602_inheritence.nim @@ -1,10 +1,11 @@ discard """ output: "seq[float]\n0" + targets: "c cpp" """ # https://github.com/nim-lang/Nim/issues/5602 -import typetraits +import typetraits, module_with_generics type Foo[T] = object of RootObj @@ -16,3 +17,8 @@ proc p[T](f: Foo[T]): T = var s: Bar[float] echo p(s).len # the bug was: p(s) should return seq[float], but returns float instead +# Test overloading and code generation when +# downcasting is required for generic types: +var d = makeDerived(10) +setBaseValue(d, 20) + From cf13c5fba48e757531b3f9cb0e3aeae7710c849c Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 4 May 2018 17:47:37 +0300 Subject: [PATCH 162/214] implement the export/except statement --- changelog.md | 2 ++ compiler/importer.nim | 13 ++++++++----- compiler/semexprs.nim | 23 +++++++++++++++++++++-- doc/manual.rst | 3 +++ tests/modules/definitions.nim | 4 ++++ tests/modules/proxy_module.nim | 3 +++ 6 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 tests/modules/definitions.nim create mode 100644 tests/modules/proxy_module.nim diff --git a/changelog.md b/changelog.md index 2a1e805739..cbefbc421e 100644 --- a/changelog.md +++ b/changelog.md @@ -108,6 +108,8 @@ - Thread-local variables can now be declared inside procs. This implies all the effects of the `global` pragma. +- Nim now supports `except` clause in the export statement. + ### Tool changes - ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed diff --git a/compiler/importer.nim b/compiler/importer.nim index f4903e6c48..a5c361864a 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -16,6 +16,13 @@ import proc evalImport*(c: PContext, n: PNode): PNode proc evalFrom*(c: PContext, n: PNode): PNode +proc readExceptSet*(n: PNode): IntSet = + assert n.kind in {nkImportExceptStmt, nkExportExceptStmt} + result = initIntSet() + for i in 1 ..< n.len: + let ident = lookups.considerQuotedIdent(n[i]) + result.incl(ident.id) + proc importPureEnumField*(c: PContext; s: PSym) = var check = strTableGet(c.importTable.symbols, s.name) if check == nil: @@ -198,9 +205,5 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode = if m != nil: n.sons[0] = newSymNode(m) addDecl(c, m, n.info) # add symbol to symbol table of module - var exceptSet = initIntSet() - for i in countup(1, sonsLen(n) - 1): - let ident = lookups.considerQuotedIdent(n.sons[i]) - exceptSet.incl(ident.id) - importAllSymbolsExcept(c, m, exceptSet) + importAllSymbolsExcept(c, m, readExceptSet(n)) #importForwarded(c, m.ast, exceptSet) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5ef9916adf..1ef284a779 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2160,9 +2160,25 @@ proc semBlock(c: PContext, n: PNode): PNode = closeScope(c) dec(c.p.nestedBlockCounter) +proc semExportExcept(c: PContext, n: PNode): PNode = + let moduleName = semExpr(c, n[0]) + if moduleName.kind != nkSym or moduleName.sym.kind != skModule: + localError(n.info, "The export/except syntax expects a module name") + return + let exceptSet = readExceptSet(n) + let exported = moduleName.sym + strTableAdd(c.module.tab, exported) + var i: TTabIter + var s = initTabIter(i, exported.tab) + while s != nil: + if s.kind in ExportableSymKinds+{skModule} and + s.name.id notin exceptSet: + strTableAdd(c.module.tab, s) + s = nextIter(i, exported.tab) + result = n + proc semExport(c: PContext, n: PNode): PNode = var x = newNodeI(n.kind, n.info) - #let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len for i in 0.. Date: Fri, 4 May 2018 19:56:03 +0300 Subject: [PATCH 163/214] bugfix: strutils.find was broken for strings with uneven number of chars For some reason, the problem was manifesting only inside the VM, it was detecting an attempt to read past the string end (i.e. the formerly accessible null byte). To catch such errors, strutils now performs static tests too. I've solved the problem by re-implementing the Boyer-Moore algotihm in a cleaner way and I took the opportunity to make some other optimisations to strutils. --- lib/pure/strutils.nim | 454 +++++++++++++++++++++++------------------- 1 file changed, 245 insertions(+), 209 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 3f01f02853..ee3072c855 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1262,21 +1262,20 @@ proc initSkipTable*(a: var SkipTable, sub: string) {.noSideEffect, rtl, extern: "nsuInitSkipTable".} = ## Preprocess table `a` for `sub`. let m = len(sub) - let m1 = m + 1 var i = 0 while i <= 0xff-7: - a[chr(i + 0)] = m1 - a[chr(i + 1)] = m1 - a[chr(i + 2)] = m1 - a[chr(i + 3)] = m1 - a[chr(i + 4)] = m1 - a[chr(i + 5)] = m1 - a[chr(i + 6)] = m1 - a[chr(i + 7)] = m1 + a[chr(i + 0)] = m + a[chr(i + 1)] = m + a[chr(i + 2)] = m + a[chr(i + 3)] = m + a[chr(i + 4)] = m + a[chr(i + 5)] = m + a[chr(i + 6)] = m + a[chr(i + 7)] = m i += 8 - for i in 0..m-1: - a[sub[i]] = m-i + for i in 0 ..< m - 1: + a[sub[i]] = m - 1 - i proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): int {.noSideEffect, rtl, extern: "nsuFindStrA".} = @@ -1284,18 +1283,29 @@ proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): ## If `last` is unspecified, it defaults to `s.high`. ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. + let last = if last==0: s.high else: last - m = len(sub) - n = last + 1 - # search: - var j = start - while j <= n - m: - block match: - for k in 0..m-1: - if sub[k] != s[k+j]: break match - return j - inc(j, a[s[j+m]]) + sLen = last - start + 1 + subLast = sub.len - 1 + + if subLast == -1: + # this was an empty needle string, + # we count this as match in the first possible position: + return start + + # This is an implementation of the Boyer-Moore Horspool algorithms + # https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm + var skip = start + + while last - skip >= subLast: + var i = subLast + while s[skip + i] == sub[i]: + if i == 0: + return skip + dec i + inc skip, a[s[skip + subLast]] + return -1 when not (defined(js) or defined(nimdoc) or defined(nimscript)): @@ -1455,23 +1465,41 @@ proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} = proc replace*(s, sub: string, by = ""): string {.noSideEffect, rtl, extern: "nsuReplaceStr".} = ## Replaces `sub` in `s` by the string `by`. - var a {.noinit.}: SkipTable result = "" - initSkipTable(a, sub) - let last = s.high - var i = 0 - while true: - let j = find(a, s, sub, i, last) - if j < 0: break - add result, substr(s, i, j - 1) + let subLen = sub.len + if subLen == 0: + for c in s: + add result, by + add result, c add result, by - if sub.len == 0: - if i < s.len: add result, s[i] - i = j + 1 - else: - i = j + sub.len - # copy the rest: - add result, substr(s, i) + return + elif subLen == 1: + # when the pattern is a single char, we use a faster + # char-based search that doesn't need a skip table: + var c = sub[0] + let last = s.high + var i = 0 + while true: + let j = find(s, c, i, last) + if j < 0: break + add result, substr(s, i, j - 1) + add result, by + i = j + subLen + # copy the rest: + add result, substr(s, i) + else: + var a {.noinit.}: SkipTable + initSkipTable(a, sub) + let last = s.high + var i = 0 + while true: + let j = find(a, s, sub, i, last) + if j < 0: break + add result, substr(s, i, j - 1) + add result, by + i = j + subLen + # copy the rest: + add result, substr(s, i) proc replace*(s: string, sub, by: char): string {.noSideEffect, rtl, extern: "nsuReplaceChar".} = @@ -1492,6 +1520,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, ## Each occurrence of `sub` has to be surrounded by word boundaries ## (comparable to ``\\w`` in regular expressions), otherwise it is not ## replaced. + if sub.len == 0: return s const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} var a {.noinit.}: SkipTable result = "" @@ -2326,236 +2355,243 @@ proc removePrefix*(s: var string, prefix: string) {. s.delete(0, prefix.len - 1) when isMainModule: - doAssert align("abc", 4) == " abc" - doAssert align("a", 0) == "a" - doAssert align("1232", 6) == " 1232" - doAssert align("1232", 6, '#') == "##1232" + proc nonStaticTests = + doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" + doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." + doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" + doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" + doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in + ["1,0e-11", "1,0e-011"] + # bug #6589 + doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" - doAssert alignLeft("abc", 4) == "abc " - doAssert alignLeft("a", 0) == "a" - doAssert alignLeft("1232", 6) == "1232 " - doAssert alignLeft("1232", 6, '#') == "1232##" + doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" + doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" - let - inp = """ this is a long text -- muchlongerthan10chars and here - it goes""" - outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes" - doAssert wordWrap(inp, 10, false) == outp + block: # formatSize tests + doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" + doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" + doAssert formatSize(4096) == "4KiB" + doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB" + doAssert formatSize(4096, includeSpace=true) == "4 KiB" + doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB" - let - longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow""" - longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow" - doAssert wordWrap(longInp, 8, true) == longOutp + block: # formatEng tests + doAssert formatEng(0, 2, trim=false) == "0.00" + doAssert formatEng(0, 2) == "0" + doAssert formatEng(53, 2, trim=false) == "53.00" + doAssert formatEng(0.053, 2, trim=false) == "53.00e-3" + doAssert formatEng(0.053, 4, trim=false) == "53.0000e-3" + doAssert formatEng(0.053, 4, trim=true) == "53e-3" + doAssert formatEng(0.053, 0) == "53e-3" + doAssert formatEng(52731234) == "52.731234e6" + doAssert formatEng(-52731234) == "-52.731234e6" + doAssert formatEng(52731234, 1) == "52.7e6" + doAssert formatEng(-52731234, 1) == "-52.7e6" + doAssert formatEng(52731234, 1, decimalSep=',') == "52,7e6" + doAssert formatEng(-52731234, 1, decimalSep=',') == "-52,7e6" - doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" - doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." - doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" - doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" - doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in - ["1,0e-11", "1,0e-011"] - # bug #6589 - doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" + doAssert formatEng(4100, siPrefix=true, unit="V") == "4.1 kV" + doAssert formatEng(4.1, siPrefix=true, unit="V", useUnitSpace=true) == "4.1 V" + doAssert formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space + doAssert formatEng(4100, siPrefix=true) == "4.1 k" + doAssert formatEng(4.1, siPrefix=true, unit="", useUnitSpace=true) == "4.1 " # Includes space + doAssert formatEng(4100, siPrefix=true, unit="") == "4.1 k" + doAssert formatEng(4100) == "4.1e3" + doAssert formatEng(4100, unit="V", useUnitSpace=true) == "4.1e3 V" + doAssert formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 " + # Don't use SI prefix as number is too big + doAssert formatEng(3.1e22, siPrefix=true, unit="a", useUnitSpace=true) == "31e21 a" + # Don't use SI prefix as number is too small + doAssert formatEng(3.1e-25, siPrefix=true, unit="A", useUnitSpace=true) == "310e-27 A" - doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" - doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" + proc staticTests = + doAssert align("abc", 4) == " abc" + doAssert align("a", 0) == "a" + doAssert align("1232", 6) == " 1232" + doAssert align("1232", 6, '#') == "##1232" - block: # formatSize tests - doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" - doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" - doAssert formatSize(4096) == "4KiB" - doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB" - doAssert formatSize(4096, includeSpace=true) == "4 KiB" - doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB" + doAssert alignLeft("abc", 4) == "abc " + doAssert alignLeft("a", 0) == "a" + doAssert alignLeft("1232", 6) == "1232 " + doAssert alignLeft("1232", 6, '#') == "1232##" - doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == - "The cat eats fish." + let + inp = """ this is a long text -- muchlongerthan10chars and here + it goes""" + outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes" + doAssert wordWrap(inp, 10, false) == outp - doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " - doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" + let + longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow""" + longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow" + doAssert wordWrap(longInp, 8, true) == longOutp - doAssert "-lda-ldz -ld abc".replaceWord("") == "lda-ldz ld abc" - doAssert "oo".replace("", "abc") == "abcoabcoabc" + doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == + "The cat eats fish." - type MyEnum = enum enA, enB, enC, enuD, enE - doAssert parseEnum[MyEnum]("enu_D") == enuD + doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " + doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" - doAssert parseEnum("invalid enum value", enC) == enC + doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc" + doAssert "oo".replace("", "abc") == "abcoabcoabc" - doAssert center("foo", 13) == " foo " - doAssert center("foo", 0) == "foo" - doAssert center("foo", 3, fillChar = 'a') == "foo" - doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" + type MyEnum = enum enA, enB, enC, enuD, enE + doAssert parseEnum[MyEnum]("enu_D") == enuD - doAssert count("foofoofoo", "foofoo") == 1 - doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 - doAssert count("foofoofoo", 'f') == 3 - doAssert count("foofoofoobar", {'f','b'}) == 4 + doAssert parseEnum("invalid enum value", enC) == enC - doAssert strip(" foofoofoo ") == "foofoofoo" - doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" - doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" - doAssert strip("stripme but don't strip this stripme", - chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == - " but don't strip this " - doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" - doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" + doAssert center("foo", 13) == " foo " + doAssert center("foo", 0) == "foo" + doAssert center("foo", 3, fillChar = 'a') == "foo" + doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" - doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" + doAssert count("foofoofoo", "foofoo") == 1 + doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 + doAssert count("foofoofoo", 'f') == 3 + doAssert count("foofoofoobar", {'f','b'}) == 4 - doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" - doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", "PEOPLE!")) == "HELLO PEOPLE!" - doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" + doAssert strip(" foofoofoo ") == "foofoofoo" + doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" + doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" + doAssert strip("stripme but don't strip this stripme", + chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == + " but don't strip this " + doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" + doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" - doAssert isAlphaAscii('r') - doAssert isAlphaAscii('A') - doAssert(not isAlphaAscii('$')) + doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" - doAssert isAlphaAscii("Rasp") - doAssert isAlphaAscii("Args") - doAssert(not isAlphaAscii("$Tomato")) + doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" + doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", "PEOPLE!")) == "HELLO PEOPLE!" + doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" - doAssert isAlphaNumeric('3') - doAssert isAlphaNumeric('R') - doAssert(not isAlphaNumeric('!')) + doAssert isAlphaAscii('r') + doAssert isAlphaAscii('A') + doAssert(not isAlphaAscii('$')) - doAssert isAlphaNumeric("34ABc") - doAssert isAlphaNumeric("Rad") - doAssert isAlphaNumeric("1234") - doAssert(not isAlphaNumeric("@nose")) + doAssert isAlphaAscii("Rasp") + doAssert isAlphaAscii("Args") + doAssert(not isAlphaAscii("$Tomato")) - doAssert isDigit('3') - doAssert(not isDigit('a')) - doAssert(not isDigit('%')) + doAssert isAlphaNumeric('3') + doAssert isAlphaNumeric('R') + doAssert(not isAlphaNumeric('!')) - doAssert isDigit("12533") - doAssert(not isDigit("12.33")) - doAssert(not isDigit("A45b")) + doAssert isAlphaNumeric("34ABc") + doAssert isAlphaNumeric("Rad") + doAssert isAlphaNumeric("1234") + doAssert(not isAlphaNumeric("@nose")) - doAssert isSpaceAscii('\t') - doAssert isSpaceAscii('\l') - doAssert(not isSpaceAscii('A')) + doAssert isDigit('3') + doAssert(not isDigit('a')) + doAssert(not isDigit('%')) - doAssert isSpaceAscii("\t\l \v\r\f") - doAssert isSpaceAscii(" ") - doAssert(not isSpaceAscii("ABc \td")) + doAssert isDigit("12533") + doAssert(not isDigit("12.33")) + doAssert(not isDigit("A45b")) - doAssert(isNilOrWhitespace("")) - doAssert(isNilOrWhitespace(" ")) - doAssert(isNilOrWhitespace("\t\l \v\r\f")) - doAssert(not isNilOrWhitespace("ABc \td")) + doAssert isSpaceAscii('\t') + doAssert isSpaceAscii('\l') + doAssert(not isSpaceAscii('A')) - doAssert isLowerAscii('a') - doAssert isLowerAscii('z') - doAssert(not isLowerAscii('A')) - doAssert(not isLowerAscii('5')) - doAssert(not isLowerAscii('&')) + doAssert isSpaceAscii("\t\l \v\r\f") + doAssert isSpaceAscii(" ") + doAssert(not isSpaceAscii("ABc \td")) - doAssert isLowerAscii("abcd") - doAssert(not isLowerAscii("abCD")) - doAssert(not isLowerAscii("33aa")) + doAssert(isNilOrWhitespace("")) + doAssert(isNilOrWhitespace(" ")) + doAssert(isNilOrWhitespace("\t\l \v\r\f")) + doAssert(not isNilOrWhitespace("ABc \td")) - doAssert isUpperAscii('A') - doAssert(not isUpperAscii('b')) - doAssert(not isUpperAscii('5')) - doAssert(not isUpperAscii('%')) + doAssert isLowerAscii('a') + doAssert isLowerAscii('z') + doAssert(not isLowerAscii('A')) + doAssert(not isLowerAscii('5')) + doAssert(not isLowerAscii('&')) - doAssert isUpperAscii("ABC") - doAssert(not isUpperAscii("AAcc")) - doAssert(not isUpperAscii("A#$")) + doAssert isLowerAscii("abcd") + doAssert(not isLowerAscii("abCD")) + doAssert(not isLowerAscii("33aa")) - doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"] - doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"] - doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""] - doAssert rsplit(":foo:bar", sep=':') == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep=':', maxsplit=2) == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep=':', maxsplit=3) == @["", "foo", "bar"] - doAssert rsplit("foothebar", sep="the") == @["foo", "bar"] + doAssert isUpperAscii('A') + doAssert(not isUpperAscii('b')) + doAssert(not isUpperAscii('5')) + doAssert(not isUpperAscii('%')) - doAssert(unescape(r"\x013", "", "") == "\x013") + doAssert isUpperAscii("ABC") + doAssert(not isUpperAscii("AAcc")) + doAssert(not isUpperAscii("A#$")) - doAssert join(["foo", "bar", "baz"]) == "foobarbaz" - doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" - doAssert join([1, 2, 3]) == "123" - doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" + doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"] + doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"] + doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""] + doAssert rsplit(":foo:bar", sep=':') == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep=':', maxsplit=2) == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep=':', maxsplit=3) == @["", "foo", "bar"] + doAssert rsplit("foothebar", sep="the") == @["foo", "bar"] - doAssert """~~!!foo + doAssert(unescape(r"\x013", "", "") == "\x013") + + doAssert join(["foo", "bar", "baz"]) == "foobarbaz" + doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" + doAssert join([1, 2, 3]) == "123" + doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" + + doAssert """~~!!foo ~~!!bar ~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz" - doAssert """~~!!foo + doAssert """~~!!foo ~~!!bar ~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz" - doAssert """~~foo + doAssert """~~foo ~~ bar ~~ baz""".unindent(4, "~") == "foo\n bar\n baz" - doAssert """foo + doAssert """foo bar baz """.unindent(4) == "foo\nbar\nbaz\n" - doAssert """foo + doAssert """foo bar baz """.unindent(2) == "foo\n bar\n baz\n" - doAssert """foo + doAssert """foo bar baz """.unindent(100) == "foo\nbar\nbaz\n" - doAssert """foo + doAssert """foo foo bar """.unindent() == "foo\nfoo\nbar\n" - let s = " this is an example " - let s2 = ":this;is;an:example;;" + let s = " this is an example " + let s2 = ":this;is;an:example;;" - doAssert s.split() == @["", "this", "is", "an", "example", "", ""] - doAssert s2.split(seps={':', ';'}) == @["", "this", "is", "an", "example", "", ""] - doAssert s.split(maxsplit=4) == @["", "this", "is", "an", "example "] - doAssert s.split(' ', maxsplit=1) == @["", "this is an example "] - doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example "] + doAssert s.split() == @["", "this", "is", "an", "example", "", ""] + doAssert s2.split(seps={':', ';'}) == @["", "this", "is", "an", "example", "", ""] + doAssert s.split(maxsplit=4) == @["", "this", "is", "an", "example "] + doAssert s.split(' ', maxsplit=1) == @["", "this is an example "] + doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example "] - doAssert s.splitWhitespace() == @["this", "is", "an", "example"] - doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example "] - doAssert s.splitWhitespace(maxsplit=2) == @["this", "is", "an example "] - doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example "] - doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"] + doAssert s.splitWhitespace() == @["this", "is", "an", "example"] + doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example "] + doAssert s.splitWhitespace(maxsplit=2) == @["this", "is", "an example "] + doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example "] + doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"] - block: # formatEng tests - doAssert formatEng(0, 2, trim=false) == "0.00" - doAssert formatEng(0, 2) == "0" - doAssert formatEng(53, 2, trim=false) == "53.00" - doAssert formatEng(0.053, 2, trim=false) == "53.00e-3" - doAssert formatEng(0.053, 4, trim=false) == "53.0000e-3" - doAssert formatEng(0.053, 4, trim=true) == "53e-3" - doAssert formatEng(0.053, 0) == "53e-3" - doAssert formatEng(52731234) == "52.731234e6" - doAssert formatEng(-52731234) == "-52.731234e6" - doAssert formatEng(52731234, 1) == "52.7e6" - doAssert formatEng(-52731234, 1) == "-52.7e6" - doAssert formatEng(52731234, 1, decimalSep=',') == "52,7e6" - doAssert formatEng(-52731234, 1, decimalSep=',') == "-52,7e6" + block: # startsWith / endsWith char tests + var s = "abcdef" + doAssert s.startsWith('a') + doAssert s.startsWith('b') == false + doAssert s.endsWith('f') + doAssert s.endsWith('a') == false + doAssert s.endsWith('\0') == false - doAssert formatEng(4100, siPrefix=true, unit="V") == "4.1 kV" - doAssert formatEng(4.1, siPrefix=true, unit="V", useUnitSpace=true) == "4.1 V" - doAssert formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space - doAssert formatEng(4100, siPrefix=true) == "4.1 k" - doAssert formatEng(4.1, siPrefix=true, unit="", useUnitSpace=true) == "4.1 " # Includes space - doAssert formatEng(4100, siPrefix=true, unit="") == "4.1 k" - doAssert formatEng(4100) == "4.1e3" - doAssert formatEng(4100, unit="V", useUnitSpace=true) == "4.1e3 V" - doAssert formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 " - # Don't use SI prefix as number is too big - doAssert formatEng(3.1e22, siPrefix=true, unit="a", useUnitSpace=true) == "31e21 a" - # Don't use SI prefix as number is too small - doAssert formatEng(3.1e-25, siPrefix=true, unit="A", useUnitSpace=true) == "310e-27 A" + #echo("strutils tests passed") - block: # startsWith / endsWith char tests - var s = "abcdef" - doAssert s.startsWith('a') - doAssert s.startsWith('b') == false - doAssert s.endsWith('f') - doAssert s.endsWith('a') == false - doAssert s.endsWith('\0') == false + nonStaticTests() + staticTests() + static: staticTests() - #echo("strutils tests passed") From 56230071263f9884ed14ab25784834a20dd73c0e Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 4 May 2018 20:05:05 +0300 Subject: [PATCH 164/214] Fix the compilation of terminal.nim on Windows --- lib/pure/terminal.nim | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index db16c23b30..8b5dcf0c50 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -40,10 +40,7 @@ const fgPrefix = "\x1b[38;2;" bgPrefix = "\x1b[48;2;" ansiResetCode* = "\e[0m" - -when not defined(windows): - const - stylePrefix = "\e[" + stylePrefix = "\e[" when defined(windows): import winlean, os From 6758fbd06e5cd88b620939b60deb5bfa00345efc Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sat, 5 May 2018 17:02:29 +0300 Subject: [PATCH 165/214] Export an 'escapeXml' proc from xmldom The interface is similar to escapeJson --- lib/pure/terminal.nim | 2 +- lib/pure/xmldom.nim | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 8b5dcf0c50..fcca4d5d74 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -621,7 +621,7 @@ proc ansiForegroundColorCode*(color: Color): string = colorsFGCache[color] = result template ansiForegroundColorCode*(color: static[Color]): string = - let rgb = extractRGB(color) + const rgb = extractRGB(color) (static(fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m")) proc ansiBackgroundColorCode*(color: Color): string = diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index c38d360263..8cd47aa395 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -1069,17 +1069,15 @@ proc splitData*(textNode: PText, offset: int): PText = var newNode: PText = textNode.fOwnerDocument.createTextNode(right) return newNode - # ProcessingInstruction proc target*(pi: PProcessingInstruction): string = ## Returns the Processing Instructions target return pi.fTarget - -# --Other stuff-- -# Writer -proc addEscaped(s: string): string = +proc escapeXml*(s: string; result: var string) = + ## Prepares a string for insertion into a XML document + ## by escaping the XML special characters. result = "" for c in items(s): case c @@ -1089,11 +1087,20 @@ proc addEscaped(s: string): string = of '"': result.add(""") else: result.add(c) +proc escapeXml*(s: string): string = + ## Prepares a string for insertion into a XML document + ## by escaping the XML special characters. + result = newStringOfCap(s.len + s.len shr 4) + escapeXml(s, result) + +# --Other stuff-- +# Writer + proc nodeToXml(n: PNode, indent: int = 0): string = result = spaces(indent) & "<" & n.nodeName if not isNil(n.attributes): for i in items(n.attributes): - result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"") + result.add(" " & i.name & "=\"" & escapeXml(i.value) & "\"") if isNil(n.childNodes) or n.childNodes.len() == 0: result.add("/>") # No idea why this doesn't need a \n :O @@ -1106,7 +1113,7 @@ proc nodeToXml(n: PNode, indent: int = 0): string = result.add(nodeToXml(i, indent + 2)) of TextNode: result.add(spaces(indent * 2)) - result.add(addEscaped(i.nodeValue)) + result.add(escapeXml(i.nodeValue)) of CDataSectionNode: result.add(spaces(indent * 2)) result.add("") From 7cf87dfac62d68d1d9ef7fbedca05b9950b71ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Tue, 8 May 2018 12:02:48 +0200 Subject: [PATCH 166/214] VM fix for refs --- compiler/vm.nim | 10 ++++++++-- tests/vm/tref.nim | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tests/vm/tref.nim diff --git a/compiler/vm.nim b/compiler/vm.nim index 6c36a14580..27135d2e77 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -210,8 +210,14 @@ proc putIntoNode(n: var PNode; x: TFullReg) = of rkInt: n.intVal = x.intVal of rkFloat: n.floatVal = x.floatVal of rkNode: - if nfIsRef in x.node.flags: n = x.node - else: n[] = x.node[] + if nfIsRef in x.node.flags: + n = x.node + else: + let destIsRef = nfIsRef in n.flags + n[] = x.node[] + # Ref-ness must be kept for the destination + if destIsRef: + n.flags.incl nfIsRef of rkRegisterAddr: putIntoNode(n, x.regAddr[]) of rkNodeAddr: n[] = x.nodeAddr[][] diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim new file mode 100644 index 0000000000..517a67fb00 --- /dev/null +++ b/tests/vm/tref.nim @@ -0,0 +1,12 @@ +static: + var + a: ref string + b: ref string + new a + + a[] = "Hello world" + b = a + + b[5] = 'c' + doAssert a[] == "Hellocworld" + doAssert b[] == "Hellocworld" \ No newline at end of file From 9bde9a1404a979e9a19601a1355f893565d4f218 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Tue, 8 May 2018 16:50:36 -0500 Subject: [PATCH 167/214] Add nimble dir to path via finish --- tools/finish.nim | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tools/finish.nim b/tools/finish.nim index b5ef78b65b..4f2c725953 100644 --- a/tools/finish.nim +++ b/tools/finish.nim @@ -187,12 +187,14 @@ when defined(windows): proc main() = when defined(windows): - let desiredPath = expandFilename(getCurrentDir() / "bin") + let nimDesiredPath = expandFilename(getCurrentDir() / "bin") + let nimbleDesiredPath = expandFilename(getEnv("USERPROFILE") / ".nimble" / "bin") let p = tryGetUnicodeValue(r"Environment", "Path", HKEY_CURRENT_USER) & ";" & tryGetUnicodeValue( r"System\CurrentControlSet\Control\Session Manager\Environment", "Path", HKEY_LOCAL_MACHINE) - var alreadyInPath = false + var nimAlreadyInPath = false + var nimbleAlreadyInPath = false var mingWchoices: seq[string] = @[] var incompat: seq[string] = @[] for x in p.split(';'): @@ -200,18 +202,29 @@ proc main() = let y = try: expandFilename(if x[0] == '"' and x[^1] == '"': substr(x, 1, x.len-2) else: x) except: "" - if y.cmpIgnoreCase(desiredPath) == 0: alreadyInPath = true - if y.toLowerAscii.contains("mingw"): + if y.cmpIgnoreCase(nimDesiredPath) == 0: + nimAlreadyInPath = true + elif y.cmpIgnoreCase(nimbleDesiredPath) == 0: + nimbleAlreadyInPath = true + elif y.toLowerAscii.contains("mingw"): if dirExists(y): if checkGccArch(y): mingWchoices.add y else: incompat.add y - if alreadyInPath: - echo "bin/nim.exe is already in your PATH [Skipping]" + if nimAlreadyInPath: + echo "bin\\nim.exe is already in your PATH [Skipping]" else: if askBool("nim.exe is not in your PATH environment variable.\n" & "Should it be added permanently? (y/n) "): - addToPathEnv(desiredPath) + addToPathEnv(nimDesiredPath) + + if nimbleAlreadyInPath: + echo nimbleDesiredPath & " is already in your PATH [Skipping]" + else: + if askBool(nimbleDesiredPath & " is not in your PATH environment variable.\n" & + "Should it be added permanently? (y/n) "): + addToPathEnv(nimbleDesiredPath) + if mingWchoices.len == 0: # No mingw in path, so try a few locations: let alternative = tryDirs(incompat, defaultMingwLocations()) From 80f17f94053dbf79e851ac2c90dd6e108c178a61 Mon Sep 17 00:00:00 2001 From: Lolo Iccl Date: Sat, 5 May 2018 05:33:54 +0900 Subject: [PATCH 168/214] Add proc hash for HashSet and for OrderedSet close #7772 --- lib/pure/collections/sets.nim | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 32b6387ad4..0019f8e3a5 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -120,6 +120,11 @@ iterator items*[A](s: HashSet[A]): A = for h in 0..high(s.data): if isFilled(s.data[h].hcode): yield s.data[h].key +proc hash*[A](x: HashSet[A]): Hash = + ## hashing of HashSet + for item in x: result = result !& hash(item) + result = !$result + const growthFactor = 2 @@ -690,6 +695,11 @@ iterator items*[A](s: OrderedSet[A]): A = forAllOrderedPairs: yield s.data[h].key +proc hash*[A](x: OrderedSet[A]): Hash = + ## hashing of OrderedSet + for item in x: result = result !& hash(item) + result = !$result + iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] = assert s.isValid, "The set needs to be initialized" forAllOrderedPairs: From ee8313da3ff19d9340285c7177db84e1c62fc108 Mon Sep 17 00:00:00 2001 From: Lolo Iccl Date: Sat, 5 May 2018 06:20:44 +0900 Subject: [PATCH 169/214] Modify previous commit Modify previous commit to use data[h].hcode in proc hash for HashSet and for OrderedSet. --- lib/pure/collections/sets.nim | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 0019f8e3a5..900f281e96 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -120,9 +120,11 @@ iterator items*[A](s: HashSet[A]): A = for h in 0..high(s.data): if isFilled(s.data[h].hcode): yield s.data[h].key -proc hash*[A](x: HashSet[A]): Hash = +proc hash*[A](s: HashSet[A]): Hash = ## hashing of HashSet - for item in x: result = result !& hash(item) + assert s.isValid, "The set needs to be initialized." + for h in 0..high(s.data): + result = result !& s.data[h].hcode result = !$result const @@ -695,9 +697,11 @@ iterator items*[A](s: OrderedSet[A]): A = forAllOrderedPairs: yield s.data[h].key -proc hash*[A](x: OrderedSet[A]): Hash = +proc hash*[A](s: OrderedSet[A]): Hash = ## hashing of OrderedSet - for item in x: result = result !& hash(item) + assert s.isValid, "The set needs to be initialized." + forAllOrderedPairs: + result = result !& s.data[h].hcode result = !$result iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] = From 5c7b66e07a3811b3fa0b8e7bbfe4cf25a6361d3a Mon Sep 17 00:00:00 2001 From: Lolo Iccl Date: Sat, 5 May 2018 08:06:29 +0900 Subject: [PATCH 170/214] Modify previous commit and add tests --- lib/pure/collections/sets.nim | 7 +++-- tests/collections/tsets.nim | 52 +++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 900f281e96..94bdbb8609 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -18,7 +18,7 @@ ## that ``=`` performs a copy of the set. import - hashes, math + hashes, math, algorithm {.pragma: myShallow.} when not defined(nimhygiene): @@ -123,8 +123,11 @@ iterator items*[A](s: HashSet[A]): A = proc hash*[A](s: HashSet[A]): Hash = ## hashing of HashSet assert s.isValid, "The set needs to be initialized." + var hcs: seq[Hash] for h in 0..high(s.data): - result = result !& s.data[h].hcode + hcs.add(s.data[h].hcode) + for hc in sorted(hcs, cmp[int]): + result = result !& hc result = !$result const diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim index 6139560bd2..be624ffe87 100644 --- a/tests/collections/tsets.nim +++ b/tests/collections/tsets.nim @@ -1,4 +1,6 @@ import sets +import hashes +import algorithm block setEquality: var @@ -35,7 +37,7 @@ block setWithSequences: doAssert( not s.contains(@[4, 5, 6]) ) block setClearWorked: - var s = initSet[char]() + var s = initSet[char]() for c in "this is a test": s.incl(c) @@ -68,12 +70,58 @@ block orderedSetClearWorked: for c in "eat at joes": s.incl(c) - r = "" + r = "" for c in items(s): add(r, c) doAssert r == "zeat jos" +block hashForHashedSet: + let + seq1 = "This is the test." + seq2 = "the test is This." + s1 = seq1.toSet() + s2 = seq2.toSet() + var hashSeq: seq[Hash] = @[] + doAssert s1 == s2 + doAssert hash(s1) == hash(s2) + for c in seq1: + if (not (hash(c) in hashSeq)): + hashSeq.add(hash(c)) + doAssert hash(s1) == hash(sorted(hashSeq, cmp[Hash])) +block hashForOrderdSet: + let + str = "This is the test." + rstr = str.reversed + var + s1 = initOrderedSet[char]() + s2 = initOrderedSet[char]() + r = initOrderedSet[char]() + expected: Hash + added: seq[char] = @[] + reversed: Hash + radded: seq[char] = @[] + expected = 0 + for c in str: + if (not (c in added)): + expected = expected !& hash(c) + added.add(c) + s1.incl(c) + s2.incl(c) + expected = !$expected + doAssert hash(s1) == expected + doAssert hash(s1) == hash(s2) + doAssert hash(s1) != hash(r) + + reversed = 0 + for c in rstr: + if (not (c in radded)): + reversed = reversed !& hash(c) + radded.add(c) + r.incl(c) + reversed = !$reversed + doAssert hash(r) == reversed + doAssert hash(s1) != reversed From af591544c59e9b05e539f4583f1143776bb8a9e4 Mon Sep 17 00:00:00 2001 From: Lolo Iccl Date: Tue, 8 May 2018 22:09:37 +0900 Subject: [PATCH 171/214] Modify hash for HashSet to use `xor` to mix hash of items. --- lib/pure/collections/sets.nim | 7 ++----- tests/collections/tsets.nim | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 94bdbb8609..59c90bc2ba 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -18,7 +18,7 @@ ## that ``=`` performs a copy of the set. import - hashes, math, algorithm + hashes, math {.pragma: myShallow.} when not defined(nimhygiene): @@ -123,11 +123,8 @@ iterator items*[A](s: HashSet[A]): A = proc hash*[A](s: HashSet[A]): Hash = ## hashing of HashSet assert s.isValid, "The set needs to be initialized." - var hcs: seq[Hash] for h in 0..high(s.data): - hcs.add(s.data[h].hcode) - for hc in sorted(hcs, cmp[int]): - result = result !& hc + result = result xor s.data[h].hcode result = !$result const diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim index be624ffe87..61e14260af 100644 --- a/tests/collections/tsets.nim +++ b/tests/collections/tsets.nim @@ -85,10 +85,6 @@ block hashForHashedSet: var hashSeq: seq[Hash] = @[] doAssert s1 == s2 doAssert hash(s1) == hash(s2) - for c in seq1: - if (not (hash(c) in hashSeq)): - hashSeq.add(hash(c)) - doAssert hash(s1) == hash(sorted(hashSeq, cmp[Hash])) block hashForOrderdSet: let From 9048bcc54b5fe8d0ae8c24b9cf7454cfa897ce5a Mon Sep 17 00:00:00 2001 From: Mathias Stearn Date: Sat, 28 Apr 2018 18:06:11 -0400 Subject: [PATCH 172/214] Add connectUnix and bindUnix to net docs fixes #7715 --- lib/pure/net.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 06bf126655..fc04ef1af4 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -960,7 +960,7 @@ when defined(posix) and not defined(nimdoc): raise newException(ValueError, "socket path too long") copyMem(addr result.sun_path, path.cstring, path.len + 1) -when defined(posix): +when defined(posix) or defined(nimdoc): proc connectUnix*(socket: Socket, path: string) = ## Connects to Unix socket on `path`. ## This only works on Unix-style systems: Mac OS X, BSD and Linux From 61e57cfa137544ebbb915ce2ed5da9afae4375ef Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 May 2018 10:49:51 +0200 Subject: [PATCH 173/214] big refactoring: parser compiles again --- compiler/ast.nim | 20 +- compiler/astalgo.nim | 8 +- compiler/commands.nim | 533 +++++++++++++++-------------- compiler/condsyms.nim | 71 +--- compiler/configuration.nim | 389 +++++++++++++++++++++ compiler/extccomp.nim | 296 ++++++++-------- compiler/idgen.nim | 12 +- compiler/lexer.nim | 65 ++-- compiler/msgs.nim | 674 +++++-------------------------------- compiler/nim.nim | 2 +- compiler/nimblecmd.nim | 25 +- compiler/nimconf.nim | 105 +++--- compiler/options.nim | 137 +++++--- compiler/parser.nim | 43 ++- compiler/scriptconfig.nim | 4 +- 15 files changed, 1156 insertions(+), 1228 deletions(-) create mode 100644 compiler/configuration.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index b8202abe60..6785702f1c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1564,15 +1564,17 @@ proc getInt*(a: PNode): BiggestInt = case a.kind of nkCharLit..nkUInt64Lit: result = a.intVal else: - internalError(a.info, "getInt") - result = 0 + #internalError(a.info, "getInt") + doAssert false, "getInt" + #result = 0 proc getFloat*(a: PNode): BiggestFloat = case a.kind of nkFloatLiterals: result = a.floatVal else: - internalError(a.info, "getFloat") - result = 0.0 + doAssert false, "getFloat" + #internalError(a.info, "getFloat") + #result = 0.0 proc getStr*(a: PNode): string = case a.kind @@ -1581,16 +1583,18 @@ proc getStr*(a: PNode): string = # let's hope this fixes more problems than it creates: result = nil else: - internalError(a.info, "getStr") - result = "" + doAssert false, "getStr" + #internalError(a.info, "getStr") + #result = "" proc getStrOrChar*(a: PNode): string = case a.kind of nkStrLit..nkTripleStrLit: result = a.strVal of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal)) else: - internalError(a.info, "getStrOrChar") - result = "" + doAssert false, "getStrOrChar" + #internalError(a.info, "getStrOrChar") + #result = "" proc isGenericRoutine*(s: PSym): bool = case s.kind diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 196ac86903..f9311d4cec 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -180,7 +180,7 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym = result = lookupInRecord(n.sons[i], field) if result != nil: return of nkRecCase: - if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord") + if (n.sons[0].kind != nkSym): return nil result = lookupInRecord(n.sons[0], field) if result != nil: return for i in countup(1, sonsLen(n) - 1): @@ -188,10 +188,10 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym = of nkOfBranch, nkElse: result = lookupInRecord(lastSon(n.sons[i]), field) if result != nil: return - else: internalError(n.info, "lookupInRecord(record case branch)") + else: return nil of nkSym: if n.sym.name.id == field.id: result = n.sym - else: internalError(n.info, "lookupInRecord()") + else: return nil proc getModule(s: PSym): PSym = result = s @@ -203,7 +203,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym = if list.sons[i].kind == nkSym: result = list.sons[i].sym if result.name.id == ident.id: return - else: internalError(list.info, "getSymFromList") + else: return nil result = nil proc hashNode(p: RootRef): Hash = diff --git a/compiler/commands.nim b/compiler/commands.nim index 204baaa16e..46ade667e5 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -18,7 +18,6 @@ template bootSwitch(name, expr, userString) = bootSwitch(usedRelease, defined(release), "-d:release") bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise") -bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas") bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm") bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep") bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational") @@ -27,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none") import os, msgs, options, nversion, condsyms, strutils, extccomp, platform, - wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils + wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, configuration # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") @@ -36,24 +35,15 @@ bootSwitch(usedNativeStacktrace, "-d:nativeStackTrace") bootSwitch(usedFFI, hasFFI, "-d:useFFI") - -proc writeCommandLineUsage*() - type TCmdLinePass* = enum passCmd1, # first pass over the command line passCmd2, # second pass over the command line passPP # preprocessor called processCommand() -proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) -proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef) - -# implementation - const HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" & - "Compiled at $4 $5\n" & + "Compiled at $4\n" & "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n" const @@ -68,7 +58,7 @@ const proc getCommandLineDesc(): string = result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name, CompileDate, CompileTime]) & + CPU[platform.hostCPU].name, CompileDate]) & Usage proc helpOnError(pass: TCmdLinePass) = @@ -80,7 +70,7 @@ proc writeAdvancedUsage(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(`%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name, CompileDate, CompileTime]) & + CPU[platform.hostCPU].name, CompileDate]) & AdvancedUsage, {msgStdout}) msgQuit(0) @@ -89,7 +79,7 @@ proc writeFullhelp(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(`%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name, CompileDate, CompileTime]) & + CPU[platform.hostCPU].name, CompileDate]) & Usage & AdvancedUsage, {msgStdout}) msgQuit(0) @@ -98,7 +88,7 @@ proc writeVersionInfo(pass: TCmdLinePass) = if pass == passCmd1: msgWriteln(`%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name, CompileDate, CompileTime]), + CPU[platform.hostCPU].name, CompileDate]), {msgStdout}) const gitHash = gorge("git log -n 1 --format=%H").strip @@ -106,15 +96,12 @@ proc writeVersionInfo(pass: TCmdLinePass) = msgWriteln("git hash: " & gitHash, {msgStdout}) msgWriteln("active boot switches:" & usedRelease & - usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas & + usedTinyC & usedGnuReadline & usedNativeStacktrace & usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC, {msgStdout}) msgQuit(0) -var - helpWritten: bool - -proc writeCommandLineUsage() = +proc writeCommandLineUsage*(helpWritten: var bool) = if not helpWritten: msgWriteln(getCommandLineDesc(), {msgStdout}) helpWritten = true @@ -123,11 +110,16 @@ proc addPrefix(switch: string): string = if len(switch) == 1: result = "-" & switch else: result = "--" & switch -proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) = - if switch == " ": localError(info, errInvalidCmdLineOption, "-") - else: localError(info, errInvalidCmdLineOption, addPrefix(switch)) +const + errInvalidCmdLineOption = "invalid command line option: '$1'" + errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found" + errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found" -proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, +proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) = + if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-") + else: localError(conf, info, errInvalidCmdLineOption % addPrefix(switch)) + +proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TCmdLinePass, info: TLineInfo) = cmd = "" var i = 0 @@ -140,46 +132,41 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, inc(i) if i >= len(switch): arg = "" elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1) - else: invalidCmdLineOption(pass, switch, info) + else: invalidCmdLineOption(conf, pass, switch, info) -proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass, +proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize of "on": gOptions = gOptions + op of "off": gOptions = gOptions - op - else: localError(info, errOnOrOffExpectedButXFound, arg) + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) -proc processOnOffSwitchOrList(op: TOptions, arg: string, pass: TCmdLinePass, +proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo): bool = result = false case arg.normalize of "on": gOptions = gOptions + op of "off": gOptions = gOptions - op - else: - if arg == "list": - result = true - else: - localError(info, errOnOffOrListExpectedButXFound, arg) + of "list": result = true + else: localError(conf, info, errOnOffOrListExpectedButXFound % arg) -proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass, +proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize of "on": gGlobalOptions = gGlobalOptions + op of "off": gGlobalOptions = gGlobalOptions - op - else: localError(info, errOnOrOffExpectedButXFound, arg) + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) -proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = - if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch)) +proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = + if arg == "": + localError(conf, info, "argument for command line option expected: '$1'" % addPrefix(switch)) -proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = - if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch)) - -var - enableNotes: TNoteKinds - disableNotes: TNoteKinds +proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = + if arg != "": + localError(conf, info, "invalid argument for command line option: '$1'" % addPrefix(switch)) proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, - info: TLineInfo; orig: string) = + info: TLineInfo; orig: string; conf: ConfigRef) = var id = "" # arg = "X]:on|off" var i = 0 var n = hintMin @@ -187,35 +174,40 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, add(id, arg[i]) inc(i) if i < len(arg) and (arg[i] == ']'): inc(i) - else: invalidCmdLineOption(pass, orig, info) + else: invalidCmdLineOption(conf, pass, orig, info) if i < len(arg) and (arg[i] in {':', '='}): inc(i) - else: invalidCmdLineOption(pass, orig, info) + else: invalidCmdLineOption(conf, pass, orig, info) if state == wHint: - let x = findStr(msgs.HintsToStr, id) + let x = findStr(configuration.HintsToStr, id) if x >= 0: n = TNoteKind(x + ord(hintMin)) - else: localError(info, "unknown hint: " & id) + else: localError(conf, info, "unknown hint: " & id) else: - let x = findStr(msgs.WarningsToStr, id) + let x = findStr(configuration.WarningsToStr, id) if x >= 0: n = TNoteKind(x + ord(warnMin)) - else: localError(info, "unknown warning: " & id) + else: localError(conf, info, "unknown warning: " & id) case substr(arg, i).normalize of "on": - incl(gNotes, n) - incl(gMainPackageNotes, n) - incl(enableNotes, n) + incl(conf.notes, n) + incl(conf.mainPackageNotes, n) + incl(conf.enableNotes, n) of "off": - excl(gNotes, n) - excl(gMainPackageNotes, n) - incl(disableNotes, n) - excl(ForeignPackageNotes, n) - else: localError(info, errOnOrOffExpectedButXFound, arg) + excl(conf.notes, n) + excl(conf.mainPackageNotes, n) + incl(conf.disableNotes, n) + excl(conf.foreignPackageNotes, n) + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) -proc processCompile(filename: string) = - var found = findFile(filename) +proc processCompile(conf: ConfigRef; filename: string) = + var found = findFile(conf, filename) if found == "": found = filename - extccomp.addExternalFileToCompile(found) + extccomp.addExternalFileToCompile(conf, found) -proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = +const + errNoneBoehmRefcExpectedButXFound = "'none', 'boehm' or 'refc' expected, but '$1' found" + errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found" + errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found" + +proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool = case switch.normalize of "gc": case arg.normalize @@ -227,13 +219,13 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = of "go": result = gSelectedGC == gcGo of "none": result = gSelectedGC == gcNone of "stack", "regions": result = gSelectedGC == gcRegions - else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) + else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "opt": case arg.normalize of "speed": result = contains(gOptions, optOptimizeSpeed) of "size": result = contains(gOptions, optOptimizeSize) of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {} - else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) + else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg) of "verbosity": result = $gVerbosity == arg of "app": case arg.normalize @@ -243,12 +235,12 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = not contains(gGlobalOptions, optGenGuiApp) of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and not contains(gGlobalOptions, optGenGuiApp) - else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) + else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg) of "dynliboverride": - result = isDynlibOverride(arg) - else: invalidCmdLineOption(passCmd1, switch, info) + result = isDynlibOverride(conf, arg) + else: invalidCmdLineOption(conf, passCmd1, switch, info) -proc testCompileOption*(switch: string, info: TLineInfo): bool = +proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool = case switch.normalize of "debuginfo": result = contains(gGlobalOptions, optCDebug) of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly) @@ -286,9 +278,9 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool = of "implicitstatic": result = contains(gOptions, optImplicitStatic) of "patterns": result = contains(gOptions, optPatterns) of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace) - else: invalidCmdLineOption(passCmd1, switch, info) + else: invalidCmdLineOption(conf, passCmd1, switch, info) -proc processPath(path: string, info: TLineInfo, +proc processPath(conf: ConfigRef; path: string, info: TLineInfo, notRelativeToProj = false): string = let p = if os.isAbsolute(path) or '$' in path: path @@ -297,12 +289,12 @@ proc processPath(path: string, info: TLineInfo, else: options.gProjectPath / path try: - result = pathSubs(p, info.toFullPath().splitFile().dir) + result = pathSubs(conf, p, info.toFullPath().splitFile().dir) except ValueError: - localError(info, "invalid path: " & p) + localError(conf, info, "invalid path: " & p) result = p -proc processCfgPath(path: string, info: TLineInfo): string = +proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): string = let path = if path[0] == '"': strutils.unescape(path) else: path let basedir = info.toFullPath().splitFile().dir let p = if os.isAbsolute(path) or '$' in path: @@ -310,225 +302,228 @@ proc processCfgPath(path: string, info: TLineInfo): string = else: basedir / path try: - result = pathSubs(p, basedir) + result = pathSubs(conf, p, basedir) except ValueError: - localError(info, "invalid path: " & p) + localError(conf, info, "invalid path: " & p) result = p -proc trackDirty(arg: string, info: TLineInfo) = +const + errInvalidNumber = "$1 is not a valid number" + +proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) = var a = arg.split(',') - if a.len != 4: localError(info, errTokenExpected, - "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN") + if a.len != 4: localError(conf, info, + "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected") var line, column: int if parseUtils.parseInt(a[2], line) <= 0: - localError(info, errInvalidNumber, a[1]) + localError(conf, info, errInvalidNumber % a[1]) if parseUtils.parseInt(a[3], column) <= 0: - localError(info, errInvalidNumber, a[2]) + localError(conf, info, errInvalidNumber % a[2]) - let dirtyOriginalIdx = a[1].fileInfoIdx + let dirtyOriginalIdx = fileInfoIdx(conf, a[1]) if dirtyOriginalIdx.int32 >= 0: msgs.setDirtyFile(dirtyOriginalIdx, a[0]) gTrackPos = newLineInfo(dirtyOriginalIdx, line, column) -proc track(arg: string, info: TLineInfo) = +proc track(conf: ConfigRef; arg: string, info: TLineInfo) = var a = arg.split(',') - if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN") + if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected") var line, column: int if parseUtils.parseInt(a[1], line) <= 0: - localError(info, errInvalidNumber, a[1]) + localError(conf, info, errInvalidNumber % a[1]) if parseUtils.parseInt(a[2], column) <= 0: - localError(info, errInvalidNumber, a[2]) - gTrackPos = newLineInfo(a[0], line, column) + localError(conf, info, errInvalidNumber % a[2]) + gTrackPos = newLineInfo(conf, a[0], line, column) -proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = +proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = if pass in {passCmd2, passPP}: - expectArg(switch, arg, pass, info) - options.inclDynlibOverride(arg) + expectArg(conf, switch, arg, pass, info) + options.inclDynlibOverride(conf, arg) -proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef) = +proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; + conf: ConfigRef) = var theOS: TSystemOS cpu: TSystemCPU key, val: string case switch.normalize of "path", "p": - expectArg(switch, arg, pass, info) - addPath(if pass == passPP: processCfgPath(arg, info) else: processPath(arg, info), info) + expectArg(conf, switch, arg, pass, info) + addPath(conf, if pass == passPP: processCfgPath(conf, arg, info) else: processPath(conf, arg, info), info) of "nimblepath", "babelpath": # keep the old name for compat if pass in {passCmd2, passPP} and not options.gNoNimblePath: - expectArg(switch, arg, pass, info) - var path = processPath(arg, info, notRelativeToProj=true) + expectArg(conf, switch, arg, pass, info) + var path = processPath(conf, arg, info, notRelativeToProj=true) let nimbleDir = getEnv("NIMBLE_DIR") if nimbleDir.len > 0 and pass == passPP: path = nimbleDir / "pkgs" - nimblePath(path, info) + nimblePath(conf, path, info) of "nonimblepath", "nobabelpath": - expectNoArg(switch, arg, pass, info) - disableNimblePath() + expectNoArg(conf, switch, arg, pass, info) + disableNimblePath(conf) of "excludepath": - expectArg(switch, arg, pass, info) - let path = processPath(arg, info) + expectArg(conf, switch, arg, pass, info) + let path = processPath(conf, arg, info) - options.searchPaths.keepItIf( cmpPaths(it, path) != 0 ) - options.lazyPaths.keepItIf( cmpPaths(it, path) != 0 ) + options.searchPaths.keepItIf(cmpPaths(it, path) != 0) + options.lazyPaths.keepItIf(cmpPaths(it, path) != 0) if (len(path) > 0) and (path[len(path) - 1] == DirSep): let strippedPath = path[0 .. (len(path) - 2)] - options.searchPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) - options.lazyPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) + options.searchPaths.keepItIf(cmpPaths(it, strippedPath) != 0) + options.lazyPaths.keepItIf(cmpPaths(it, strippedPath) != 0) of "nimcache": - expectArg(switch, arg, pass, info) - options.nimcacheDir = processPath(arg, info, true) + expectArg(conf, switch, arg, pass, info) + options.nimcacheDir = processPath(conf, arg, info, true) of "out", "o": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) options.outFile = arg of "docseesrcurl": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) options.docSeeSrcUrl = arg of "mainmodule", "m": discard "allow for backwards compatibility, but don't do anything" of "define", "d": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) if {':', '='} in arg: - splitSwitch(arg, key, val, pass, info) - defineSymbol(key, val) + splitSwitch(conf, arg, key, val, pass, info) + defineSymbol(conf.symbols, key, val) else: - defineSymbol(arg) + defineSymbol(conf.symbols, arg) of "undef", "u": - expectArg(switch, arg, pass, info) - undefSymbol(arg) + expectArg(conf, switch, arg, pass, info) + undefSymbol(conf.symbols, arg) of "symbol": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) # deprecated, do nothing of "compile": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: processCompile(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: processCompile(conf, arg) of "link": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: addExternalFileToLink(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: addExternalFileToLink(conf, arg) of "debuginfo": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optCDebug) of "embedsrc": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optEmbedOrigSrc) of "compileonly", "c": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optCompileOnly) of "nolinking": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optNoLinking) of "nomain": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optNoMain) of "forcebuild", "f": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optForceFullMake) of "project": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) gWholeProject = true of "gc": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) case arg.normalize of "boehm": gSelectedGC = gcBoehm - defineSymbol("boehmgc") + defineSymbol(conf.symbols, "boehmgc") of "refc": gSelectedGC = gcRefc of "v2": gSelectedGC = gcV2 of "markandsweep": gSelectedGC = gcMarkAndSweep - defineSymbol("gcmarkandsweep") + defineSymbol(conf.symbols, "gcmarkandsweep") of "generational": gSelectedGC = gcGenerational - defineSymbol("gcgenerational") + defineSymbol(conf.symbols, "gcgenerational") of "go": gSelectedGC = gcGo - defineSymbol("gogc") + defineSymbol(conf.symbols, "gogc") of "none": gSelectedGC = gcNone - defineSymbol("nogc") + defineSymbol(conf.symbols, "nogc") of "stack", "regions": gSelectedGC= gcRegions - defineSymbol("gcregions") - else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) + defineSymbol(conf.symbols, "gcregions") + else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "warnings", "w": - if processOnOffSwitchOrList({optWarns}, arg, pass, info): listWarnings() - of "warning": processSpecificNote(arg, wWarning, pass, info, switch) - of "hint": processSpecificNote(arg, wHint, pass, info, switch) + if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf) + of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf) + of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf) of "hints": - if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints() - of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info) - of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info) - of "excessivestacktrace": processOnOffSwitchG({optExcessiveStackTrace}, arg, pass, info) - of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info) + if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf) + of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info) + of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info) + of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info) + of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info) of "debugger": case arg.normalize of "on", "endb": gOptions.incl optEndb - defineSymbol("endb") + defineSymbol(conf.symbols, "endb") of "off": gOptions.excl optEndb - undefSymbol("endb") + undefSymbol(conf.symbols, "endb") of "native", "gdb": incl(gGlobalOptions, optCDebug) gOptions = gOptions + {optLineDir} - {optEndb} - defineSymbol("nimTypeNames", nil) # type names are used in gdb pretty printing - undefSymbol("endb") + defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing + undefSymbol(conf.symbols, "endb") else: - localError(info, "expected endb|gdb but found " & arg) + localError(conf, info, "expected endb|gdb but found " & arg) of "profiler": - processOnOffSwitch({optProfiler}, arg, pass, info) - if optProfiler in gOptions: defineSymbol("profiler") - else: undefSymbol("profiler") + processOnOffSwitch(conf, {optProfiler}, arg, pass, info) + if optProfiler in gOptions: defineSymbol(conf.symbols, "profiler") + else: undefSymbol(conf.symbols, "profiler") of "memtracker": - processOnOffSwitch({optMemTracker}, arg, pass, info) - if optMemTracker in gOptions: defineSymbol("memtracker") - else: undefSymbol("memtracker") + processOnOffSwitch(conf, {optMemTracker}, arg, pass, info) + if optMemTracker in gOptions: defineSymbol(conf.symbols, "memtracker") + else: undefSymbol(conf.symbols, "memtracker") of "hotcodereloading": - processOnOffSwitch({optHotCodeReloading}, arg, pass, info) - if optHotCodeReloading in gOptions: defineSymbol("hotcodereloading") - else: undefSymbol("hotcodereloading") + processOnOffSwitch(conf, {optHotCodeReloading}, arg, pass, info) + if optHotCodeReloading in gOptions: defineSymbol(conf.symbols, "hotcodereloading") + else: undefSymbol(conf.symbols, "hotcodereloading") of "oldnewlines": case arg.normalize of "on": options.gOldNewlines = true - defineSymbol("nimOldNewlines") + defineSymbol(conf.symbols, "nimOldNewlines") of "off": options.gOldNewlines = false - undefSymbol("nimOldNewlines") + undefSymbol(conf.symbols, "nimOldNewlines") else: - localError(info, errOnOrOffExpectedButXFound, arg) - of "laxstrings": processOnOffSwitch({optLaxStrings}, arg, pass, info) - of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info) + localError(conf, info, errOnOrOffExpectedButXFound % arg) + of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info) + of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info) of "floatchecks": - processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info) - of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info) - of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info) - of "nilchecks": processOnOffSwitch({optNilCheck}, arg, pass, info) - of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info) - of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info) - of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info) - of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info) - of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info) - of "movechecks": processOnOffSwitch({optMoveCheck}, arg, pass, info) - of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info) - of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info) + processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info) + of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info) + of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info) + of "nilchecks": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info) + of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info) + of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info) + of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info) + of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info) + of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info) + of "movechecks": processOnOffSwitch(conf, {optMoveCheck}, arg, pass, info) + of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info) + of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info) of "deadcodeelim": discard # deprecated, dead code elim always on of "threads": - processOnOffSwitchG({optThreads}, arg, pass, info) - #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe) - of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info) - of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info) + processOnOffSwitchG(conf, {optThreads}, arg, pass, info) + #if optThreads in gGlobalOptions: incl(conf.notes, warnGcUnsafe) + of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info) + of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info) of "implicitstatic": - processOnOffSwitch({optImplicitStatic}, arg, pass, info) + processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info) of "patterns": - processOnOffSwitch({optPatterns}, arg, pass, info) + processOnOffSwitch(conf, {optPatterns}, arg, pass, info) of "opt": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) case arg.normalize of "speed": incl(gOptions, optOptimizeSpeed) @@ -539,99 +534,99 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "none": excl(gOptions, optOptimizeSpeed) excl(gOptions, optOptimizeSize) - else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) + else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg) of "app": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) case arg.normalize of "gui": incl(gGlobalOptions, optGenGuiApp) - defineSymbol("executable") - defineSymbol("guiapp") + defineSymbol(conf.symbols, "executable") + defineSymbol(conf.symbols, "guiapp") of "console": excl(gGlobalOptions, optGenGuiApp) - defineSymbol("executable") - defineSymbol("consoleapp") + defineSymbol(conf.symbols, "executable") + defineSymbol(conf.symbols, "consoleapp") of "lib": incl(gGlobalOptions, optGenDynLib) excl(gGlobalOptions, optGenGuiApp) - defineSymbol("library") - defineSymbol("dll") + defineSymbol(conf.symbols, "library") + defineSymbol(conf.symbols, "dll") of "staticlib": incl(gGlobalOptions, optGenStaticLib) excl(gGlobalOptions, optGenGuiApp) - defineSymbol("library") - defineSymbol("staticlib") - else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) + defineSymbol(conf.symbols, "library") + defineSymbol(conf.symbols, "staticlib") + else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg) of "passc", "t": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(conf, arg) of "passl", "l": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg) of "cincludes": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: cIncludes.add processPath(conf, arg, info) of "clibdir": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: cLibs.add arg.processPath(info) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: cLibs.add processPath(conf, arg, info) of "clib": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: cLinkedLibs.add processPath(conf, arg, info) of "header": - if config != nil: config.headerFile = arg + if conf != nil: conf.headerFile = arg incl(gGlobalOptions, optGenIndex) of "index": - processOnOffSwitchG({optGenIndex}, arg, pass, info) + processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info) of "import": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: implicitImports.add arg of "include": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) if pass in {passCmd2, passPP}: implicitIncludes.add arg of "listcmd": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optListCmd) of "genmapping": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optGenMapping) of "os": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) if pass in {passCmd1, passPP}: theOS = platform.nameToOS(arg) - if theOS == osNone: localError(info, errUnknownOS, arg) + if theOS == osNone: localError(conf, info, "unknown OS: '$1'" % arg) elif theOS != platform.hostOS: setTarget(theOS, targetCPU) of "cpu": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) if pass in {passCmd1, passPP}: cpu = platform.nameToCPU(arg) - if cpu == cpuNone: localError(info, errUnknownCPU, arg) + if cpu == cpuNone: localError(conf, info, "unknown CPU: '$1'" % arg) elif cpu != platform.hostCPU: setTarget(targetOS, cpu) of "run", "r": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optRun) of "verbosity": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) gVerbosity = parseInt(arg) - gNotes = NotesVerbosity[gVerbosity] - incl(gNotes, enableNotes) - excl(gNotes, disableNotes) - gMainPackageNotes = gNotes + conf.notes = NotesVerbosity[gVerbosity] + incl(conf.notes, conf.enableNotes) + excl(conf.notes, conf.disableNotes) + conf.mainPackageNotes = conf.notes of "parallelbuild": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) gNumberOfProcessors = parseInt(arg) of "version", "v": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) writeVersionInfo(pass) of "advanced": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) writeAdvancedUsage(pass) of "fullhelp": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) writeFullhelp(pass) of "help", "h": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) helpOnError(pass) of "symbolfiles": case arg.normalize @@ -640,101 +635,103 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "writeonly": gSymbolFiles = writeOnlySf of "readonly": gSymbolFiles = readOnlySf of "v2": gSymbolFiles = v2Sf - else: localError(info, errOnOrOffExpectedButXFound, arg) + else: localError(conf, info, "invalid option for --symbolFiles: " & arg) of "skipcfg": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optSkipConfigFile) of "skipprojcfg": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optSkipProjConfigFile) of "skipusercfg": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optSkipUserConfigFile) of "skipparentcfg": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optSkipParentConfigFiles) of "genscript", "gendeps": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optGenScript) incl(gGlobalOptions, optCompileOnly) - of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info) + of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info) of "lib": - expectArg(switch, arg, pass, info) - libpath = processPath(arg, info, notRelativeToProj=true) + expectArg(conf, switch, arg, pass, info) + libpath = processPath(conf, arg, info, notRelativeToProj=true) of "putenv": - expectArg(switch, arg, pass, info) - splitSwitch(arg, key, val, pass, info) + expectArg(conf, switch, arg, pass, info) + splitSwitch(conf, arg, key, val, pass, info) os.putEnv(key, val) of "cc": - expectArg(switch, arg, pass, info) - setCC(arg) + expectArg(conf, switch, arg, pass, info) + setCC(conf, arg, info) of "track": - expectArg(switch, arg, pass, info) - track(arg, info) + expectArg(conf, switch, arg, pass, info) + track(conf, arg, info) of "trackdirty": - expectArg(switch, arg, pass, info) - trackDirty(arg, info) + expectArg(conf, switch, arg, pass, info) + trackDirty(conf, arg, info) of "suggest": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) gIdeCmd = ideSug of "def": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) gIdeCmd = ideDef of "eval": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) gEvalExpr = arg of "context": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) gIdeCmd = ideCon of "usages": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) gIdeCmd = ideUse of "stdout": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optStdout) of "listfullpaths": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) gListFullPaths = true of "dynliboverride": - dynlibOverride(switch, arg, pass, info) + dynlibOverride(conf, switch, arg, pass, info) of "dynliboverrideall": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) gDynlibOverrideAll = true of "cs": # only supported for compatibility. Does nothing. - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) of "experimental": if arg.len == 0: - config.features.incl oldExperimentalFeatures + conf.features.incl oldExperimentalFeatures else: try: - config.features.incl parseEnum[Feature](arg) + conf.features.incl parseEnum[Feature](arg) except ValueError: - localError(info, "unknown experimental feature") + localError(conf, info, "unknown experimental feature") of "nocppexceptions": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optNoCppExceptions) - defineSymbol("noCppExceptions") + defineSymbol(conf.symbols, "noCppExceptions") of "cppdefine": - expectArg(switch, arg, pass, info) - if config != nil: - config.cppDefine(arg) + expectArg(conf, switch, arg, pass, info) + if conf != nil: + conf.cppDefine(arg) of "newruntime": - expectNoArg(switch, arg, pass, info) - doAssert(config != nil) - incl(config.features, destructor) - defineSymbol("nimNewRuntime") + expectNoArg(conf, switch, arg, pass, info) + doAssert(conf != nil) + incl(conf.features, destructor) + defineSymbol(conf.symbols, "nimNewRuntime") of "cppcompiletonamespace": - expectNoArg(switch, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) useNimNamespace = true - defineSymbol("cppCompileToNamespace") + defineSymbol(conf.symbols, "cppCompileToNamespace") else: - if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) - else: invalidCmdLineOption(pass, switch, info) + if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg) + else: invalidCmdLineOption(conf, pass, switch, info) -proc processCommand(switch: string, pass: TCmdLinePass; config: ConfigRef) = +template gCmdLineInfo*(): untyped = newLineInfo(FileIndex(0), 1, 1) + +proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) = var cmd, arg: string - splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) + splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo) processSwitch(cmd, arg, pass, gCmdLineInfo, config) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index f8a75e68e3..773c0faf95 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -12,77 +12,30 @@ import strtabs, platform, strutils, idents -# We need to use a StringTableRef here as defined symbols are always guaranteed -# to be style insensitive. Otherwise hell would break lose. -var gSymbols: StringTableRef - const catNone = "false" -proc defineSymbol*(symbol: string, value: string = "true") = - gSymbols[symbol] = value +proc defineSymbol*(symbols: StringTableRef; symbol: string, value: string = "true") = + symbols[symbol] = value -proc undefSymbol*(symbol: string) = - gSymbols[symbol] = catNone +proc undefSymbol*(symbols: StringTableRef; symbol: string) = + symbols[symbol] = catNone -proc isDefined*(symbol: string): bool = - if gSymbols.hasKey(symbol): - result = gSymbols[symbol] != catNone - elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0: - result = true - elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0: - result = true - else: - case symbol.normalize - of "x86": result = targetCPU == cpuI386 - of "itanium": result = targetCPU == cpuIa64 - of "x8664": result = targetCPU == cpuAmd64 - of "posix", "unix": - result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos, - osQnx, osAtari, osAix, - osHaiku, osVxWorks, osSolaris, osNetbsd, - osFreebsd, osOpenbsd, osDragonfly, osMacosx, - osAndroid} - of "linux": - result = targetOS in {osLinux, osAndroid} - of "bsd": - result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly} - of "emulatedthreadvars": - result = platform.OS[targetOS].props.contains(ospLacksThreadVars) - of "msdos": result = targetOS == osDos - of "mswindows", "win32": result = targetOS == osWindows - of "macintosh": result = targetOS in {osMacos, osMacosx} - of "sunos": result = targetOS == osSolaris - of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian - of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian - of "cpu8": result = CPU[targetCPU].bit == 8 - of "cpu16": result = CPU[targetCPU].bit == 16 - of "cpu32": result = CPU[targetCPU].bit == 32 - of "cpu64": result = CPU[targetCPU].bit == 64 - of "nimrawsetjmp": - result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd, - osDragonfly, osMacosx} - else: discard +#proc lookupSymbol*(symbols: StringTableRef; symbol: string): string = +# result = if isDefined(symbol): gSymbols[symbol] else: nil -proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s) - -proc lookupSymbol*(symbol: string): string = - result = if isDefined(symbol): gSymbols[symbol] else: nil - -proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s) - -iterator definedSymbolNames*: string = - for key, val in pairs(gSymbols): +iterator definedSymbolNames*(symbols: StringTableRef): string = + for key, val in pairs(symbols): if val != catNone: yield key -proc countDefinedSymbols*(): int = +proc countDefinedSymbols*(symbols: StringTableRef): int = result = 0 - for key, val in pairs(gSymbols): + for key, val in pairs(symbols): if val != catNone: inc(result) -proc initDefines*() = - gSymbols = newStringTable(modeStyleInsensitive) +proc initDefines*(symbols: StringTableRef) = # for bootstrapping purposes and old code: + template defineSymbol(s) = symbols.defineSymbol(s) defineSymbol("nimhygiene") defineSymbol("niminheritable") defineSymbol("nimmixin") diff --git a/compiler/configuration.nim b/compiler/configuration.nim new file mode 100644 index 0000000000..452a999648 --- /dev/null +++ b/compiler/configuration.nim @@ -0,0 +1,389 @@ +# +# +# The Nim Compiler +# (c) Copyright 2018 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module contains the rather excessive configuration object that +## needs to be passed around to everything so that the compiler becomes +## more useful as a library. + +import tables + +const + explanationsBaseUrl* = "https://nim-lang.org/docs/manual" + +type + TMsgKind* = enum + errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated, + errUser, + warnCannotOpenFile, + warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, + warnDeprecated, warnConfigDeprecated, + warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, + warnUnknownSubstitutionX, warnLanguageXNotSupported, + warnFieldXNotSupported, warnCommentXIgnored, + warnTypelessParam, + warnUseBase, warnWriteToForeignHeap, warnUnsafeCode, + warnEachIdentIsTuple, warnShadowIdent, + warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, + warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, + warnInconsistentSpacing, warnUser, + hintSuccess, hintSuccessX, + hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, + hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, + hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, + hintConditionAlwaysTrue, hintName, hintPattern, + hintExecuting, hintLinking, hintDependency, + hintSource, hintPerformance, hintStackTrace, hintGCStats, + hintUser, hintUserRaw + +const + MsgKindToStr*: array[TMsgKind, string] = [ + errUnknown: "unknown error", + errInternal: "internal error: $1", + errIllFormedAstX: "illformed AST: $1", + errCannotOpenFile: "cannot open '$1'", + errGenerated: "$1", + errUser: "$1", + warnCannotOpenFile: "cannot open '$1'", + warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored", + warnXIsNeverRead: "'$1' is never read", + warnXmightNotBeenInit: "'$1' might not have been initialized", + warnDeprecated: "$1 is deprecated", + warnConfigDeprecated: "config file '$1' is deprecated", + warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)", + warnUnknownMagic: "unknown magic '$1' might crash the compiler", + warnRedefinitionOfLabel: "redefinition of label '$1'", + warnUnknownSubstitutionX: "unknown substitution '$1'", + warnLanguageXNotSupported: "language '$1' not supported", + warnFieldXNotSupported: "field '$1' not supported", + warnCommentXIgnored: "comment '$1' ignored", + warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'", + warnUseBase: "use {.base.} for base methods; baseless methods are deprecated", + warnWriteToForeignHeap: "write to foreign heap", + warnUnsafeCode: "unsafe code: '$1'", + warnEachIdentIsTuple: "each identifier is a tuple", + warnShadowIdent: "shadowed identifier: '$1'", + warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.", + warnProveField: "cannot prove that field '$1' is accessible", + warnProveIndex: "cannot prove index '$1' is valid", + warnGcUnsafe: "not GC-safe: '$1'", + warnGcUnsafe2: "$1", + warnUninit: "'$1' might not have been initialized", + warnGcMem: "'$1' uses GC'ed memory", + warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.", + warnLockLevel: "$1", + warnResultShadowed: "Special variable 'result' is shadowed.", + warnInconsistentSpacing: "Number of spaces around '$#' is not consistent", + warnUser: "$1", + hintSuccess: "operation successful", + hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", + hintLineTooLong: "line too long", + hintXDeclaredButNotUsed: "'$1' is declared but not used", + hintConvToBaseNotNeeded: "conversion to base object is not needed", + hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless", + hintExprAlwaysX: "expression evaluates always to '$1'", + hintQuitCalled: "quit() called", + hintProcessing: "$1", + hintCodeBegin: "generated code listing:", + hintCodeEnd: "end of listing", + hintConf: "used config file '$1'", + hintPath: "added path: '$1'", + hintConditionAlwaysTrue: "condition is always true: '$1'", + hintName: "name should be: '$1'", + hintPattern: "$1", + hintExecuting: "$1", + hintLinking: "", + hintDependency: "$1", + hintSource: "$1", + hintPerformance: "$1", + hintStackTrace: "$1", + hintGCStats: "$1", + hintUser: "$1", + hintUserRaw: "$1"] + +const + WarningsToStr* = ["CannotOpenFile", "OctalEscape", + "XIsNeverRead", "XmightNotBeenInit", + "Deprecated", "ConfigDeprecated", + "SmallLshouldNotBeUsed", "UnknownMagic", + "RedefinitionOfLabel", "UnknownSubstitutionX", + "LanguageXNotSupported", "FieldXNotSupported", + "CommentXIgnored", + "TypelessParam", "UseBase", "WriteToForeignHeap", + "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", + "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", + "GcMem", "Destructor", "LockLevel", "ResultShadowed", + "Spacing", "User"] + + HintsToStr* = ["Success", "SuccessX", "LineTooLong", + "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", + "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", + "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency", + "Source", "Performance", "StackTrace", "GCStats", + "User", "UserRaw"] + +const + fatalMin* = errUnknown + fatalMax* = errInternal + errMin* = errUnknown + errMax* = errUser + warnMin* = warnCannotOpenFile + warnMax* = pred(hintSuccess) + hintMin* = hintSuccess + hintMax* = high(TMsgKind) + +static: + doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1 + doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1 + +type + TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints + TNoteKinds* = set[TNoteKind] + +const + NotesVerbosity*: array[0..3, TNoteKinds] = [ + {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit, + warnProveField, warnProveIndex, + warnGcUnsafe, + hintSuccessX, hintPath, hintConf, + hintProcessing, hintPattern, + hintDependency, + hintExecuting, hintLinking, + hintCodeBegin, hintCodeEnd, + hintSource, hintStackTrace, + hintGCStats}, + {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit, + warnProveField, warnProveIndex, + warnGcUnsafe, + hintPath, + hintDependency, + hintCodeBegin, hintCodeEnd, + hintSource, hintStackTrace, + hintGCStats}, + {low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit}, + {low(TNoteKind)..high(TNoteKind)}] + +#[ +errStringLiteralExpected: "string literal expected", +errIntLiteralExpected: "integer literal expected", +errIdentifierExpected: "identifier expected, but found '$1'", +errNewlineExpected: "newline expected, but found '$1'", +errInvalidModuleName: "invalid module name: '$1'", +errRecursiveDependencyX: "recursive dependency: '$1'", +errOnOrOffExpected: "'on' or 'off' expected", +errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected", +errInvalidPragma: "invalid pragma", +errUnknownPragma: "unknown pragma: '$1'", +errAtPopWithoutPush: "'pop' without a 'push' pragma", +errEmptyAsm: "empty asm statement", +errInvalidIndentation: "invalid indentation", +errExceptionAlreadyHandled: "exception already handled", +errYieldNotAllowedHere: "'yield' only allowed in an iterator", +errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator", +errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions", +errCannotReturnExpr: "current routine cannot return an expression", +errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type", +errAttemptToRedefine: "redefinition of '$1'", +errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma", +errStmtExpected: "statement expected", +errInvalidLabel: "'$1' is no label", +errInvalidCmdLineOption: "invalid command line option: '$1'", +errCmdLineArgExpected: "argument for command line option expected: '$1'", +errCmdLineNoArgExpected: "invalid argument for command line option: '$1'", +errInvalidVarSubstitution: "invalid variable substitution in '$1'", +errUnknownVar: "unknown variable: '$1'", +errUnknownCcompiler: "unknown C compiler: '$1'", +errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found", +errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found", +errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found", +errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected", +errInvalidMultipleAsgn: "multiple assignment is not allowed", +errColonOrEqualsExpected: "':' or '=' expected, but found '$1'", +errUndeclaredField: "undeclared field: '$1'", +errUndeclaredRoutine: "attempting to call undeclared routine: '$1'", +errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier", +errTypeExpected: "type expected", +errSystemNeeds: "system module needs '$1'", +errExecutionOfProgramFailed: "execution of an external program failed: '$1'", +errNotOverloadable: "overloaded '$1' leads to ambiguous calls", +errInvalidArgForX: "invalid argument for '$1'", +errStmtHasNoEffect: "statement has no effect", +errXExpectsTypeOrValue: "'$1' expects a type or value", +errXExpectsArrayType: "'$1' expects an array type", +errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", +errExprXAmbiguous: "expression '$1' ambiguous in this context", +errConstantDivisionByZero: "division by zero", +errOrdinalTypeExpected: "ordinal type expected", +errOrdinalOrFloatTypeExpected: "ordinal or float type expected", +errOverOrUnderflow: "over- or underflow", +errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely", +errChrExpectsRange0_255: "'chr' expects an int in the range 0..255", +errDynlibRequiresExportc: "'dynlib' requires 'exportc'", +errUndeclaredFieldX: "undeclared field: '$1'", +errNilAccess: "attempt to access a nil address", +errIndexOutOfBounds: "index out of bounds", +errIndexTypesDoNotMatch: "index types do not match", +errBracketsInvalidForType: "'[]' operator invalid for this type", +errValueOutOfSetBounds: "value out of set bounds", +errFieldInitTwice: "field initialized twice: '$1'", +errFieldNotInit: "field '$1' not initialized", +errExprXCannotBeCalled: "expression '$1' cannot be called", +errExprHasNoType: "expression has no type", +errExprXHasNoType: "expression '$1' has no type (or is ambiguous)", +errCastNotInSafeMode: "'cast' not allowed in safe mode", +errExprCannotBeCastToX: "expression cannot be cast to $1", +errCommaOrParRiExpected: "',' or ')' expected", +errCurlyLeOrParLeExpected: "'{' or '(' expected", +errSectionExpected: "section ('type', 'proc', etc.) expected", +errRangeExpected: "range expected", +errMagicOnlyInSystem: "'magic' only allowed in system module", +errPowerOfTwoExpected: "power of two expected", +errStringMayNotBeEmpty: "string literal may not be empty", +errCallConvExpected: "calling convention expected", +errProcOnlyOneCallConv: "a proc can only have one calling convention", +errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used", +errExprMustBeBool: "expression must be of type 'bool'", +errConstExprExpected: "constant expression expected", +errDuplicateCaseLabel: "duplicate case label", +errRangeIsEmpty: "range is empty", +errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string", +errSelectorMustBeOrdinal: "selector must be of an ordinal type", +errOrdXMustNotBeNegative: "ord($1) must not be negative", +errLenXinvalid: "len($1) must be less than 32768", +errWrongNumberOfVariables: "wrong number of variables", +errExprCannotBeRaised: "only a 'ref object' can be raised", +errBreakOnlyInLoop: "'break' only allowed in loop construct", +errTypeXhasUnknownSize: "type '$1' has unknown size", +errConstNeedsConstExpr: "a constant can only be initialized with a constant expression", +errConstNeedsValue: "a constant needs a value", +errResultCannotBeOpenArray: "the result type cannot be on open array", +errSizeTooBig: "computing the type's size produced an overflow", +errSetTooBig: "set is too large", +errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal", +errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects", +errInheritanceOnlyWithEnums: "inheritance only works with an enum", +errIllegalRecursionInTypeX: "illegal recursion in type '$1'", +errCannotInstantiateX: "cannot instantiate: '$1'", +errExprHasNoAddress: "expression has no address", +errXStackEscape: "address of '$1' may not escape its stack frame", +errVarForOutParamNeededX: "for a 'var' type a variable needs to be passed; but '$1' is immutable", +errPureTypeMismatch: "type mismatch", +errTypeMismatch: "type mismatch: got <", +errButExpected: "but expected one of: ", +errButExpectedX: "but expected '$1'", +errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3", +errWrongNumberOfArguments: "wrong number of arguments", +errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", +errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", +errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar", +errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", +errImplOfXNotAllowed: "implementation of '$1' is not allowed", +errImplOfXexpected: "implementation of '$1' expected", +errNoSymbolToBorrowFromFound: "no symbol to borrow from found", +errDiscardValueX: "value of type '$1' has to be discarded", +errInvalidDiscard: "statement returns no value that can be discarded", +errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid", +errCannotBindXTwice: "cannot bind parameter '$1' twice", +errInvalidOrderInArrayConstructor: "invalid order in array constructor", +errInvalidOrderInEnumX: "invalid order in enum '$1'", +errEnumXHasHoles: "enum '$1' has holes", +errExceptExpected: "'except' or 'finally' expected", +errInvalidTry: "after catch all 'except' or 'finally' no section may follow", +errOptionExpected: "option expected, but found '$1'", +errXisNoLabel: "'$1' is not a label", +errNotAllCasesCovered: "not all cases are covered", +errUnknownSubstitionVar: "unknown substitution variable: '$1'", +errComplexStmtRequiresInd: "complex statement requires indentation", +errXisNotCallable: "'$1' is not callable", +errNoPragmasAllowedForX: "no pragmas allowed for $1", +errNoGenericParamsAllowedForX: "no generic parameters allowed for $1", +errInvalidParamKindX: "invalid param kind: '$1'", +errDefaultArgumentInvalid: "default argument invalid", +errNamedParamHasToBeIdent: "named parameter has to be an identifier", +errNoReturnTypeForX: "no return type allowed for $1", +errConvNeedsOneArg: "a type conversion needs exactly one argument", +errInvalidPragmaX: "invalid pragma: $1", +errXNotAllowedHere: "$1 not allowed here", +errInvalidControlFlowX: "invalid control flow: $1", +errXisNoType: "invalid type: '$1'", +errCircumNeedsPointer: "'[]' needs a pointer or reference type", +errInvalidExpression: "invalid expression", +errInvalidExpressionX: "invalid expression: '$1'", +errEnumHasNoValueX: "enum has no value '$1'", +errNamedExprExpected: "named expression expected", +errNamedExprNotAllowed: "named expression not allowed here", +errXExpectsOneTypeParam: "'$1' expects one type parameter", +errArrayExpectsTwoTypeParams: "array expects two type parameters", +errInvalidVisibilityX: "invalid visibility: '$1'", +errInitHereNotAllowed: "initialization not allowed here", +errXCannotBeAssignedTo: "'$1' cannot be assigned to", +errIteratorNotAllowed: "iterators can only be defined at the module's top level", +errXNeedsReturnType: "$1 needs a return type", +errNoReturnTypeDeclared: "no return type declared", +errNoCommand: "no command given", +errInvalidCommandX: "invalid command: '$1'", +errXOnlyAtModuleScope: "'$1' is only allowed at top level", +errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", +errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N", +errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N", +errInstantiationFrom: "template/generic instantiation from here", +errInvalidIndexValueForTuple: "invalid index value for tuple subscript", +errCommandExpectsFilename: "command expects a filename argument", +errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", +errXExpected: "'$1' expected", +errTIsNotAConcreteType: "'$1' is not a concrete type.", +errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'", +errInvalidSectionStart: "invalid section start", +errGridTableNotImplemented: "grid table is not implemented", +errGeneralParseError: "general parse error", +errNewSectionExpected: "new section expected", +errWhitespaceExpected: "whitespace expected, got '$1'", +errXisNoValidIndexFile: "'$1' is no valid index file", +errCannotRenderX: "cannot render reStructuredText element '$1'", +errVarVarTypeNotAllowed: "type 'var var' is not allowed", +errInstantiateXExplicitly: "instantiate '$1' explicitly", +errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", +errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", +errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " & + "because the parameter '$1' has a generic type", +errDestructorNotGenericEnough: "Destructor signature is too specific. " & + "A destructor must be associated will all instantiations of a generic type", +errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " & + "templates, macros and other inline iterators", +errXExpectsTwoArguments: "'$1' expects two arguments", +errXExpectsObjectTypes: "'$1' expects object types", +errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype", +errTooManyIterations: "interpretation requires too many iterations; " & + "if you are sure this is not a bug in your code edit " & + "compiler/vmdef.MaxLoopIterations and rebuild the compiler", +errCannotInterpretNodeX: "cannot evaluate '$1'", +errFieldXNotFound: "field '$1' cannot be found", +errInvalidConversionFromTypeX: "invalid conversion from type '$1'", +errAssertionFailed: "assertion failed", +errCannotGenerateCodeForX: "cannot generate code for '$1'", +errXRequiresOneArgument: "$1 requires one parameter", +errUnhandledExceptionX: "unhandled exception: $1", +errCyclicTree: "macro returned a cyclic abstract syntax tree", +errXisNoMacroOrTemplate: "'$1' is no macro or template", +errXhasSideEffects: "'$1' can have side effects", +errIteratorExpected: "iterator within for loop context expected", +errLetNeedsInit: "'let' symbol requires an initialization", +errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread", +errWrongSymbolX: "usage of '$1' is a user-defined error", +errIllegalCaptureX: "illegal capture '$1'", +errXCannotBeClosure: "'$1' cannot have 'closure' calling convention", +errXMustBeCompileTime: "'$1' can only be used in compile-time context", +errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1", +errCannotInferReturnType: "cannot infer the return type of the proc", +errCannotInferStaticParam: "cannot infer the value of the static param `$1`", +errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " & + "it is used as an operand to another routine and the types " & + "of the generic paramers can be inferred from the expected signature.", +errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.", +errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types", +]# diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index f8938e3af5..388bb9c9e0 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -14,7 +14,7 @@ import ropes, os, strutils, osproc, platform, condsyms, options, msgs, - std / sha1, streams + configuration, std / sha1, streams #from debuginfo import writeDebugInfo @@ -193,9 +193,9 @@ compiler bcc: pic: "", asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$1 $2", - props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, + props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasAttribute}) - + # Digital Mars C Compiler compiler dmc: @@ -376,7 +376,7 @@ proc nameToCC*(name: string): TSystemCC = return i result = ccNone -proc getConfigVar(c: TSystemCC, suffix: string): string = +proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = # use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given # for niminst support let fullSuffix = @@ -394,62 +394,63 @@ proc getConfigVar(c: TSystemCC, suffix: string): string = let fullCCname = platform.CPU[targetCPU].name & '.' & platform.OS[targetOS].name & '.' & CC[c].name & fullSuffix - result = getConfigVar(fullCCname) + result = getConfigVar(conf, fullCCname) if result.len == 0: # not overriden for this cross compilation setting? - result = getConfigVar(CC[c].name & fullSuffix) + result = getConfigVar(conf, CC[c].name & fullSuffix) else: - result = getConfigVar(CC[c].name & fullSuffix) + result = getConfigVar(conf, CC[c].name & fullSuffix) -proc setCC*(ccname: string) = +proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) = cCompiler = nameToCC(ccname) - if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname) - compileOptions = getConfigVar(cCompiler, ".options.always") + if cCompiler == ccNone: + localError(conf, info, "unknown C compiler: '$1'" % ccname) + compileOptions = getConfigVar(conf, cCompiler, ".options.always") linkOptions = "" - ccompilerpath = getConfigVar(cCompiler, ".path") - for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name) - defineSymbol(CC[cCompiler].name) + ccompilerpath = getConfigVar(conf, cCompiler, ".path") + for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name) + defineSymbol(conf.symbols, CC[cCompiler].name) proc addOpt(dest: var string, src: string) = if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ") add(dest, src) -proc addLinkOption*(option: string) = +proc addLinkOption*(conf: ConfigRef; option: string) = addOpt(linkOptions, option) -proc addCompileOption*(option: string) = +proc addCompileOption*(conf: ConfigRef; option: string) = if strutils.find(compileOptions, option, 0) < 0: addOpt(compileOptions, option) -proc addLinkOptionCmd*(option: string) = +proc addLinkOptionCmd*(conf: ConfigRef; option: string) = addOpt(linkOptionsCmd, option) -proc addCompileOptionCmd*(option: string) = +proc addCompileOptionCmd*(conf: ConfigRef; option: string) = compileOptionsCmd.add(option) -proc initVars*() = +proc initVars*(conf: ConfigRef) = # 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) - addCompileOption(getConfigVar(cCompiler, ".options.always")) + for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name) + defineSymbol(conf.symbols, CC[cCompiler].name) + addCompileOption(conf, getConfigVar(conf, cCompiler, ".options.always")) #addLinkOption(getConfigVar(cCompiler, ".options.linker")) if len(ccompilerpath) == 0: - ccompilerpath = getConfigVar(cCompiler, ".path") + ccompilerpath = getConfigVar(conf, cCompiler, ".path") -proc completeCFilePath*(cfile: string, createSubDir: bool = true): string = - result = completeGeneratedFilePath(cfile, createSubDir) +proc completeCFilePath*(conf: ConfigRef; cfile: string, createSubDir: bool = true): string = + result = completeGeneratedFilePath(conf, cfile, createSubDir) -proc toObjFile*(filename: string): string = +proc toObjFile*(conf: ConfigRef; filename: string): string = # Object file for compilation #if filename.endsWith(".cpp"): # result = changeFileExt(filename, "cpp." & CC[cCompiler].objExt) #else: result = changeFileExt(filename, CC[cCompiler].objExt) -proc addFileToCompile*(cf: Cfile) = +proc addFileToCompile*(conf: ConfigRef; cf: Cfile) = toCompile.add(cf) -proc resetCompilationLists* = +proc resetCompilationLists*(conf: ConfigRef) = toCompile.setLen 0 ## XXX: we must associate these with their originating module # when the module is loaded/unloaded it adds/removes its items @@ -457,107 +458,110 @@ proc resetCompilationLists* = # Maybe we can do that in checkDep on the other hand? externalToLink.setLen 0 -proc addExternalFileToLink*(filename: string) = +proc addExternalFileToLink*(conf: ConfigRef; filename: string) = externalToLink.insert(filename, 0) -proc execWithEcho(cmd: string, msg = hintExecuting): int = - rawMessage(msg, cmd) +proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int = + rawMessage(conf, msg, cmd) result = execCmd(cmd) -proc execExternalProgram*(cmd: string, msg = hintExecuting) = - if execWithEcho(cmd, msg) != 0: - rawMessage(errExecutionOfProgramFailed, cmd) +proc execExternalProgram*(conf: ConfigRef; cmd: string, msg = hintExecuting) = + if execWithEcho(conf, cmd, msg) != 0: + rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" % + cmd) -proc generateScript(projectFile: string, script: Rope) = +proc generateScript(conf: ConfigRef; projectFile: string, script: Rope) = let (dir, name, ext) = splitFile(projectFile) - writeRope(script, getNimcacheDir() / addFileExt("compile_" & name, + writeRope(script, getNimcacheDir(conf) / addFileExt("compile_" & name, platform.OS[targetOS].scriptExt)) - copyFile(libpath / "nimbase.h", getNimcacheDir() / "nimbase.h") + copyFile(libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h") -proc getOptSpeed(c: TSystemCC): string = - result = getConfigVar(c, ".options.speed") +proc getOptSpeed(conf: ConfigRef; c: TSystemCC): string = + result = getConfigVar(conf, c, ".options.speed") if result == "": result = CC[c].optSpeed # use default settings from this file -proc getDebug(c: TSystemCC): string = - result = getConfigVar(c, ".options.debug") +proc getDebug(conf: ConfigRef; c: TSystemCC): string = + result = getConfigVar(conf, c, ".options.debug") if result == "": result = CC[c].debug # use default settings from this file -proc getOptSize(c: TSystemCC): string = - result = getConfigVar(c, ".options.size") +proc getOptSize(conf: ConfigRef; c: TSystemCC): string = + result = getConfigVar(conf, c, ".options.size") if result == "": result = CC[c].optSize # use default settings from this file -proc noAbsolutePaths: bool {.inline.} = +proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} = # We used to check current OS != specified OS, but this makes no sense # really: Cross compilation from Linux to Linux for example is entirely # reasonable. # `optGenMapping` is included here for niminst. result = gGlobalOptions * {optGenScript, optGenMapping} != {} -proc cFileSpecificOptions(cfilename: string): string = +proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string = result = compileOptions for option in compileOptionsCmd: if strutils.find(result, option, 0) < 0: addOpt(result, option) - var trunk = splitFile(cfilename).name + let trunk = splitFile(cfilename).name if optCDebug in gGlobalOptions: - var key = trunk & ".debug" - if existsConfigVar(key): addOpt(result, getConfigVar(key)) - else: addOpt(result, getDebug(cCompiler)) + let key = trunk & ".debug" + if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) + else: addOpt(result, getDebug(conf, cCompiler)) if optOptimizeSpeed in gOptions: - var key = trunk & ".speed" - if existsConfigVar(key): addOpt(result, getConfigVar(key)) - else: addOpt(result, getOptSpeed(cCompiler)) + let key = trunk & ".speed" + if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) + else: addOpt(result, getOptSpeed(conf, cCompiler)) elif optOptimizeSize in gOptions: - var key = trunk & ".size" - if existsConfigVar(key): addOpt(result, getConfigVar(key)) - else: addOpt(result, getOptSize(cCompiler)) - var key = trunk & ".always" - if existsConfigVar(key): addOpt(result, getConfigVar(key)) + let key = trunk & ".size" + if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) + else: addOpt(result, getOptSize(conf, cCompiler)) + let key = trunk & ".always" + if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) -proc getCompileOptions: string = - result = cFileSpecificOptions("__dummy__") +proc getCompileOptions(conf: ConfigRef): string = + result = cFileSpecificOptions(conf, "__dummy__") -proc getLinkOptions: string = +proc getLinkOptions(conf: ConfigRef): string = result = linkOptions & " " & linkOptionsCmd & " " for linkedLib in items(cLinkedLibs): result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell) for libDir in items(cLibs): result.add(join([CC[cCompiler].linkDirCmd, libDir.quoteShell])) -proc needsExeExt(): bool {.inline.} = +proc needsExeExt(conf: ConfigRef): bool {.inline.} = result = (optGenScript in gGlobalOptions and targetOS == osWindows) or (platform.hostOS == osWindows) -proc getCompilerExe(compiler: TSystemCC; cfile: string): string = +proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string = result = if gCmd == cmdCompileToCpp and not cfile.endsWith(".c"): CC[compiler].cppCompiler else: CC[compiler].compilerExe if result.len == 0: - rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name) + rawMessage(conf, errGenerated, + "Compiler '$1' doesn't support the requested target" % + CC[compiler].name) -proc getLinkerExe(compiler: TSystemCC): string = +proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler - else: compiler.getCompilerExe("") + else: getCompilerExe(conf, compiler, "") -proc getCompileCFileCmd*(cfile: Cfile): string = +proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string = var c = cCompiler - var options = cFileSpecificOptions(cfile.cname) - var exe = getConfigVar(c, ".exe") - if exe.len == 0: exe = c.getCompilerExe(cfile.cname) + var options = cFileSpecificOptions(conf, cfile.cname) + var exe = getConfigVar(conf, c, ".exe") + if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname) - if needsExeExt(): exe = addFileExt(exe, "exe") + if needsExeExt(conf): exe = addFileExt(exe, "exe") if optGenDynLib in gGlobalOptions and ospNeedsPIC in platform.OS[targetOS].props: add(options, ' ' & CC[c].pic) var includeCmd, compilePattern: string - if not noAbsolutePaths(): + if not noAbsolutePaths(conf): # compute include paths: includeCmd = CC[c].includeCmd & quoteShell(libpath) @@ -567,18 +571,18 @@ proc getCompileCFileCmd*(cfile: Cfile): string = compilePattern = joinPath(ccompilerpath, exe) else: includeCmd = "" - compilePattern = c.getCompilerExe(cfile.cname) + compilePattern = getCompilerExe(conf, c, cfile.cname) - var cf = if noAbsolutePaths(): extractFilename(cfile.cname) + var cf = if noAbsolutePaths(conf): extractFilename(cfile.cname) else: cfile.cname var objfile = if cfile.obj.len == 0: - if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(): - toObjFile(cf) + if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(conf): + toObjFile(conf, cf) else: - completeCFilePath(toObjFile(cf)) - elif noAbsolutePaths(): + completeCFilePath(conf, toObjFile(conf, cf)) + elif noAbsolutePaths(conf): extractFilename(cfile.obj) else: cfile.obj @@ -587,30 +591,30 @@ proc getCompileCFileCmd*(cfile: Cfile): string = cf = quoteShell(cf) result = quoteShell(compilePattern % [ "file", cf, "objfile", objfile, "options", options, - "include", includeCmd, "nim", getPrefixDir(), - "nim", getPrefixDir(), "lib", libpath]) + "include", includeCmd, "nim", getPrefixDir(conf), + "nim", getPrefixDir(conf), "lib", libpath]) add(result, ' ') addf(result, CC[c].compileTmpl, [ "file", cf, "objfile", objfile, "options", options, "include", includeCmd, - "nim", quoteShell(getPrefixDir()), - "nim", quoteShell(getPrefixDir()), + "nim", quoteShell(getPrefixDir(conf)), + "nim", quoteShell(getPrefixDir(conf)), "lib", quoteShell(libpath)]) -proc footprint(cfile: Cfile): SecureHash = +proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = result = secureHash( $secureHashFile(cfile.cname) & platform.OS[targetOS].name & platform.CPU[targetCPU].name & extccomp.CC[extccomp.cCompiler].name & - getCompileCFileCmd(cfile)) + getCompileCFileCmd(conf, cfile)) -proc externalFileChanged(cfile: Cfile): bool = +proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}: return false - var hashFile = toGeneratedFile(cfile.cname.withPackageName, "sha1") - var currentHash = footprint(cfile) + var hashFile = toGeneratedFile(conf, cfile.cname.withPackageName, "sha1") + var currentHash = footprint(conf, cfile) var f: File if open(f, hashFile, fmRead): let oldHash = parseSecureHash(f.readLine()) @@ -623,23 +627,23 @@ proc externalFileChanged(cfile: Cfile): bool = f.writeLine($currentHash) close(f) -proc addExternalFileToCompile*(c: var Cfile) = - if optForceFullMake notin gGlobalOptions and not externalFileChanged(c): +proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) = + if optForceFullMake notin gGlobalOptions and not externalFileChanged(conf, c): c.flags.incl CfileFlag.Cached toCompile.add(c) -proc addExternalFileToCompile*(filename: string) = +proc addExternalFileToCompile*(conf: ConfigRef; filename: string) = var c = Cfile(cname: filename, - obj: toObjFile(completeCFilePath(changeFileExt(filename, ""), false)), + obj: toObjFile(conf, completeCFilePath(conf, changeFileExt(filename, ""), false)), flags: {CfileFlag.External}) - addExternalFileToCompile(c) + addExternalFileToCompile(conf, c) -proc compileCFile(list: CFileList, script: var Rope, cmds: var TStringSeq, +proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var TStringSeq, prettyCmds: var TStringSeq) = for it in list: # call the C compiler for the .c file: if it.flags.contains(CfileFlag.Cached): continue - var compileCmd = getCompileCFileCmd(it) + var compileCmd = getCompileCFileCmd(conf, it) if optCompileOnly notin gGlobalOptions: add(cmds, compileCmd) let (_, name, _) = splitFile(it.cname) @@ -648,7 +652,7 @@ proc compileCFile(list: CFileList, script: var Rope, cmds: var TStringSeq, add(script, compileCmd) add(script, tnl) -proc getLinkCmd(projectfile, objfiles: string): string = +proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = if optGenStaticLib in gGlobalOptions: var libname: string if options.outFile.len > 0: @@ -660,11 +664,11 @@ proc getLinkCmd(projectfile, objfiles: string): string = result = CC[cCompiler].buildLib % ["libfile", libname, "objfiles", objfiles] else: - var linkerExe = getConfigVar(cCompiler, ".linkerexe") - if len(linkerExe) == 0: linkerExe = cCompiler.getLinkerExe + var linkerExe = getConfigVar(conf, cCompiler, ".linkerexe") + if len(linkerExe) == 0: linkerExe = getLinkerExe(conf, cCompiler) # bug #6452: We must not use ``quoteShell`` here for ``linkerExe`` - if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe") - if noAbsolutePaths(): result = linkerExe + if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe") + if noAbsolutePaths(conf): result = linkerExe else: result = joinPath(ccompilerpath, linkerExe) let buildgui = if optGenGuiApp in gGlobalOptions: CC[cCompiler].buildGui else: "" @@ -679,60 +683,63 @@ proc getLinkCmd(projectfile, objfiles: string): string = exefile = options.outFile.expandTilde if not exefile.isAbsolute(): exefile = getCurrentDir() / exefile - if not noAbsolutePaths(): + if not noAbsolutePaths(conf): if not exefile.isAbsolute(): exefile = joinPath(splitFile(projectfile).dir, exefile) when false: if optCDebug in gGlobalOptions: writeDebugInfo(exefile.changeFileExt("ndb")) exefile = quoteShell(exefile) - let linkOptions = getLinkOptions() & " " & - getConfigVar(cCompiler, ".options.linker") - var linkTmpl = getConfigVar(cCompiler, ".linkTmpl") + let linkOptions = getLinkOptions(conf) & " " & + getConfigVar(conf, cCompiler, ".options.linker") + var linkTmpl = getConfigVar(conf, cCompiler, ".linkTmpl") if linkTmpl.len == 0: linkTmpl = CC[cCompiler].linkTmpl result = quoteShell(result % ["builddll", builddll, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, - "exefile", exefile, "nim", getPrefixDir(), "lib", libpath]) + "exefile", exefile, "nim", getPrefixDir(conf), "lib", libpath]) result.add ' ' addf(result, linkTmpl, ["builddll", builddll, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "exefile", exefile, - "nim", quoteShell(getPrefixDir()), + "nim", quoteShell(getPrefixDir(conf)), "lib", quoteShell(libpath)]) -template tryExceptOSErrorMessage(errorPrefix: string = "", body: untyped): typed = +template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped): typed = try: body except OSError: let ose = (ref OSError)(getCurrentException()) if errorPrefix.len > 0: - rawMessage(errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode) + rawMessage(conf, errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode) else: - rawMessage(errExecutionOfProgramFailed, ose.msg & " " & $ose.errorCode) + rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" % + (ose.msg & " " & $ose.errorCode)) raise -proc execLinkCmd(linkCmd: string) = - tryExceptOSErrorMessage("invocation of external linker program failed."): - execExternalProgram(linkCmd, +proc execLinkCmd(conf: ConfigRef; linkCmd: string) = + tryExceptOSErrorMessage(conf, "invocation of external linker program failed."): + execExternalProgram(conf, linkCmd, if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking) -proc execCmdsInParallel(cmds: seq[string]; prettyCb: proc (idx: int)) = +proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: int)) = let runCb = proc (idx: int, p: Process) = let exitCode = p.peekExitCode if exitCode != 0: - rawMessage(errGenerated, "execution of an external compiler program '" & + rawMessage(conf, errGenerated, "execution of an external compiler program '" & cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" & p.outputStream.readAll.strip) if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors() var res = 0 if gNumberOfProcessors <= 1: for i in countup(0, high(cmds)): - tryExceptOSErrorMessage("invocation of external compiler program failed."): - res = execWithEcho(cmds[i]) - if res != 0: rawMessage(errExecutionOfProgramFailed, cmds[i]) + tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."): + res = execWithEcho(conf, cmds[i]) + if res != 0: + rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" % + cmds[i]) else: - tryExceptOSErrorMessage("invocation of external compiler program failed."): + tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."): if optListCmd in gGlobalOptions or gVerbosity > 1: res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath}, gNumberOfProcessors, afterRunEvent=runCb) @@ -744,9 +751,10 @@ proc execCmdsInParallel(cmds: seq[string]; prettyCb: proc (idx: int)) = gNumberOfProcessors, afterRunEvent=runCb) if res != 0: if gNumberOfProcessors <= 1: - rawMessage(errExecutionOfProgramFailed, cmds.join()) + rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" % + cmds.join()) -proc callCCompiler*(projectfile: string) = +proc callCCompiler*(conf: ConfigRef; projectfile: string) = var linkCmd: string if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: @@ -758,36 +766,36 @@ proc callCCompiler*(projectfile: string) = var prettyCmds: TStringSeq = @[] let prettyCb = proc (idx: int) = echo prettyCmds[idx] - compileCFile(toCompile, script, cmds, prettyCmds) + compileCFile(conf, toCompile, script, cmds, prettyCmds) if optCompileOnly notin gGlobalOptions: - execCmdsInParallel(cmds, prettyCb) + execCmdsInParallel(conf, cmds, prettyCb) if optNoLinking notin gGlobalOptions: # call the linker: var objfiles = "" for it in externalToLink: - let objFile = if noAbsolutePaths(): it.extractFilename else: it + let objFile = if noAbsolutePaths(conf): it.extractFilename else: it add(objfiles, ' ') add(objfiles, quoteShell( addFileExt(objFile, CC[cCompiler].objExt))) for x in toCompile: - let objFile = if noAbsolutePaths(): x.obj.extractFilename else: x.obj + let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj add(objfiles, ' ') add(objfiles, quoteShell(objFile)) - linkCmd = getLinkCmd(projectfile, objfiles) + linkCmd = getLinkCmd(conf, projectfile, objfiles) if optCompileOnly notin gGlobalOptions: - execLinkCmd(linkCmd) + execLinkCmd(conf, linkCmd) else: linkCmd = "" if optGenScript in gGlobalOptions: add(script, linkCmd) add(script, tnl) - generateScript(projectfile, script) + generateScript(conf, projectfile, script) #from json import escapeJson import json -proc writeJsonBuildInstructions*(projectfile: string) = +proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) = template lit(x: untyped) = f.write x template str(x: untyped) = when compiles(escapeJson(x, buf)): @@ -797,11 +805,11 @@ proc writeJsonBuildInstructions*(projectfile: string) = else: f.write escapeJson(x) - proc cfiles(f: File; buf: var string; clist: CfileList, isExternal: bool) = + proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) = var pastStart = false for it in clist: if CfileFlag.Cached in it.flags: continue - let compileCmd = getCompileCFileCmd(it) + let compileCmd = getCompileCFileCmd(conf, it) if pastStart: lit "],\L" lit "[" str it.cname @@ -810,11 +818,11 @@ proc writeJsonBuildInstructions*(projectfile: string) = pastStart = true lit "]\L" - proc linkfiles(f: File; buf, objfiles: var string; clist: CfileList; + proc linkfiles(conf: ConfigRef; f: File; buf, objfiles: var string; clist: CfileList; llist: seq[string]) = var pastStart = false for it in llist: - let objfile = if noAbsolutePaths(): it.extractFilename + let objfile = if noAbsolutePaths(conf): it.extractFilename else: it let objstr = addFileExt(objfile, CC[cCompiler].objExt) add(objfiles, ' ') @@ -835,25 +843,25 @@ proc writeJsonBuildInstructions*(projectfile: string) = var buf = newStringOfCap(50) let file = projectfile.splitFile.name - let jsonFile = toGeneratedFile(file, "json") + let jsonFile = toGeneratedFile(conf, file, "json") var f: File if open(f, jsonFile, fmWrite): lit "{\"compile\":[\L" - cfiles(f, buf, toCompile, false) + cfiles(conf, f, buf, toCompile, false) lit "],\L\"link\":[\L" var objfiles = "" # XXX add every file here that is to link - linkfiles(f, buf, objfiles, toCompile, externalToLink) + linkfiles(conf, f, buf, objfiles, toCompile, externalToLink) lit "],\L\"linkcmd\": " - str getLinkCmd(projectfile, objfiles) + str getLinkCmd(conf, projectfile, objfiles) lit "\L}\L" close(f) -proc runJsonBuildInstructions*(projectfile: string) = +proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: string) = let file = projectfile.splitFile.name - let jsonFile = toGeneratedFile(file, "json") + let jsonFile = toGeneratedFile(conf, file, "json") try: let data = json.parseFile(jsonFile) let toCompile = data["compile"] @@ -870,32 +878,32 @@ proc runJsonBuildInstructions*(projectfile: string) = let prettyCb = proc (idx: int) = echo prettyCmds[idx] - execCmdsInParallel(cmds, prettyCb) + execCmdsInParallel(conf, cmds, prettyCb) let linkCmd = data["linkcmd"] doAssert linkCmd.kind == JString - execLinkCmd(linkCmd.getStr) + execLinkCmd(conf, linkCmd.getStr) except: echo getCurrentException().getStackTrace() quit "error evaluating JSON file: " & jsonFile -proc genMappingFiles(list: CFileList): Rope = +proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope = for it in list: addf(result, "--file:r\"$1\"$N", [rope(it.cname)]) -proc writeMapping*(gSymbolMapping: Rope) = +proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) = if optGenMapping notin gGlobalOptions: return var code = rope("[C_Files]\n") - add(code, genMappingFiles(toCompile)) + add(code, genMappingFiles(conf, toCompile)) add(code, "\n[C_Compiler]\nFlags=") - add(code, strutils.escape(getCompileOptions())) + add(code, strutils.escape(getCompileOptions(conf))) add(code, "\n[Linker]\nFlags=") - add(code, strutils.escape(getLinkOptions() & " " & - getConfigVar(cCompiler, ".options.linker"))) + add(code, strutils.escape(getLinkOptions(conf) & " " & + getConfigVar(conf, cCompiler, ".options.linker"))) add(code, "\n[Environment]\nlibpath=") add(code, strutils.escape(libpath)) - addf(code, "\n[Symbols]$n$1", [gSymbolMapping]) + addf(code, "\n[Symbols]$n$1", [symbolMapping]) writeRope(code, joinPath(gProjectPath, "mapping.txt")) diff --git a/compiler/idgen.nim b/compiler/idgen.nim index c6b1a4d074..7d103ffd7f 100644 --- a/compiler/idgen.nim +++ b/compiler/idgen.nim @@ -36,20 +36,20 @@ proc setId*(id: int) {.inline.} = proc idSynchronizationPoint*(idRange: int) = gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1 -proc toGid(f: string): string = +proc toGid(conf: ConfigRef; f: string): string = # we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this # will cause strange bugs if multiple projects are in the same folder, so # we simply use a project independent name: - result = options.completeGeneratedFilePath("nim.gid") + result = options.completeGeneratedFilePath(conf, "nim.gid") -proc saveMaxIds*(project: string) = - var f = open(project.toGid, fmWrite) +proc saveMaxIds*(conf: ConfigRef; project: string) = + var f = open(toGid(conf, project), fmWrite) f.writeLine($gFrontEndId) f.close() -proc loadMaxIds*(project: string) = +proc loadMaxIds*(conf: ConfigRef; project: string) = var f: File - if open(f, project.toGid, fmRead): + if open(f, toGid(conf, project), fmRead): var line = newStringOfCap(20) if f.readLine(line): var frontEndId = parseInt(line) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index a655873903..68348a73ed 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -17,7 +17,7 @@ import hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream, - wordrecg + wordrecg, configuration const MaxLineLength* = 80 # lines longer than this lead to a warning @@ -131,7 +131,7 @@ type # like 0b01 or r"\L" are unaffected commentOffsetA*, commentOffsetB*: int - TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string) + TErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) TLexer* = object of TBaseLexer fileIdx*: FileIndex indentAhead*: int # if > 0 an indendation has already been read @@ -234,7 +234,7 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream; cache: IdentCache; config: ConfigRef) = - openLexer(lex, filename.fileInfoIdx, inputstream, cache, config) + openLexer(lex, fileInfoIdx(config, filename), inputstream, cache, config) proc closeLexer*(lex: var TLexer) = if lex.config != nil: @@ -246,9 +246,9 @@ proc getLineInfo(L: TLexer): TLineInfo = proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) = if L.errorHandler.isNil: - msgs.message(info, msg, arg) + msgs.message(L.config, info, msg, arg) else: - L.errorHandler(info, msg, arg) + L.errorHandler(L.config, info, msg, arg) proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") = L.dispMessage(getLineInfo(L), msg, arg) @@ -341,7 +341,8 @@ proc getNumber(L: var TLexer, result: var TToken) = break if buf[pos] == '_': if buf[pos+1] notin chars: - lexMessage(L, errInvalidToken, "_") + lexMessage(L, errGenerated, + "only single underscores may occur in a token: '__' is invalid") break add(tok.literal, '_') inc(pos) @@ -355,7 +356,7 @@ proc getNumber(L: var TLexer, result: var TToken) = inc(pos) L.bufpos = pos - proc lexMessageLitNum(L: var TLexer, msg: TMsgKind, startpos: int) = + proc lexMessageLitNum(L: var TLexer, msg: string, startpos: int) = # Used to get slightly human friendlier err messages. # Note: the erroneous 'O' char in the character set is intentional const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O', @@ -376,7 +377,7 @@ proc getNumber(L: var TLexer, result: var TToken) = add(t.literal, L.buf[L.bufpos]) matchChars(L, t, {'0'..'9'}) L.bufpos = msgPos - lexMessage(L, msg, t.literal) + lexMessage(L, errGenerated, msg % t.literal) var startpos, endpos: int @@ -398,7 +399,7 @@ proc getNumber(L: var TLexer, result: var TToken) = eatChar(L, result, '0') case L.buf[L.bufpos] of 'O': - lexMessageLitNum(L, errInvalidNumberOctalCode, startpos) + lexMessageLitNum(L, "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.", startpos) of 'x', 'X': eatChar(L, result, 'x') matchUnderscoreChars(L, result, {'0'..'9', 'a'..'f', 'A'..'F'}) @@ -409,7 +410,7 @@ proc getNumber(L: var TLexer, result: var TToken) = eatChar(L, result, 'b') matchUnderscoreChars(L, result, {'0'..'1'}) else: - internalError(getLineInfo(L), "getNumber") + internalError(L.config, getLineInfo(L), "getNumber") else: matchUnderscoreChars(L, result, {'0'..'9'}) if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}): @@ -464,7 +465,7 @@ proc getNumber(L: var TLexer, result: var TToken) = result.tokType = tkInt8Lit inc(postPos) else: - lexMessageLitNum(L, errInvalidNumber, startpos) + lexMessageLitNum(L, "invalid number: '$1'", startpos) of 'u', 'U': inc(postPos) if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'): @@ -482,12 +483,12 @@ proc getNumber(L: var TLexer, result: var TToken) = else: result.tokType = tkUIntLit else: - lexMessageLitNum(L, errInvalidNumber, startpos) + lexMessageLitNum(L, "invalid number: '$1'", startpos) # Is there still a literalish char awaiting? Then it's an error! if L.buf[postPos] in literalishChars or (L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}): - lexMessageLitNum(L, errInvalidNumber, startpos) + lexMessageLitNum(L, "invalid number: '$1'", startpos) # Third stage, extract actual number L.bufpos = startpos # restore position @@ -528,7 +529,7 @@ proc getNumber(L: var TLexer, result: var TToken) = else: break else: - internalError(getLineInfo(L), "getNumber") + internalError(L.config, getLineInfo(L), "getNumber") case result.tokType of tkIntLit, tkInt64Lit: result.iNumber = xi @@ -545,7 +546,7 @@ proc getNumber(L: var TLexer, result: var TToken) = # XXX: Test this on big endian machine! of tkFloat64Lit, tkFloatLit: result.fNumber = (cast[PFloat64](addr(xi)))[] - else: internalError(getLineInfo(L), "getNumber") + else: internalError(L.config, getLineInfo(L), "getNumber") # Bounds checks. Non decimal literals are allowed to overflow the range of # the datatype as long as their pattern don't overflow _bitwise_, hence @@ -561,7 +562,7 @@ proc getNumber(L: var TLexer, result: var TToken) = if outOfRange: #echo "out of range num: ", result.iNumber, " vs ", xi - lexMessageLitNum(L, errNumberOutOfRange, startpos) + lexMessageLitNum(L, "number out of range: '$1'", startpos) else: case result.tokType @@ -590,7 +591,7 @@ proc getNumber(L: var TLexer, result: var TToken) = result.iNumber > BiggestInt(uint32.high)) else: false - if outOfRange: lexMessageLitNum(L, errNumberOutOfRange, startpos) + if outOfRange: lexMessageLitNum(L, "number out of range: '$1'", startpos) # Promote int literal to int64? Not always necessary, but more consistent if result.tokType == tkIntLit: @@ -598,9 +599,9 @@ proc getNumber(L: var TLexer, result: var TToken) = result.tokType = tkInt64Lit except ValueError: - lexMessageLitNum(L, errInvalidNumber, startpos) + lexMessageLitNum(L, "invalid number: '$1'", startpos) except OverflowError, RangeError: - lexMessageLitNum(L, errNumberOutOfRange, startpos) + lexMessageLitNum(L, "number out of range: '$1'", startpos) tokenEnd(result, postPos-1) L.bufpos = postPos @@ -627,7 +628,8 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) = case L.buf[L.bufpos] of 'n', 'N': if gOldNewlines: - if tok.tokType == tkCharLit: lexMessage(L, errNnotAllowedInCharacter) + if tok.tokType == tkCharLit: + lexMessage(L, errGenerated, "\\n not allowed in character literal") add(tok.literal, tnl) else: add(tok.literal, '\L') @@ -696,8 +698,8 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) = var xi = 0 handleDecChars(L, xi) if (xi <= 255): add(tok.literal, chr(xi)) - else: lexMessage(L, errInvalidCharacterConstant) - else: lexMessage(L, errInvalidCharacterConstant) + else: lexMessage(L, errGenerated, "invalid character constant") + else: lexMessage(L, errGenerated, "invalid character constant") proc newString(s: cstring, len: int): string = ## XXX, how come there is no support for this? @@ -761,7 +763,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) = tokenEndIgnore(tok, pos) var line2 = L.lineNumber L.lineNumber = line - lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart) + lexMessagePos(L, errGenerated, L.lineStart, "closing \"\"\" expected, but end of file reached") L.lineNumber = line2 L.bufpos = pos break @@ -784,7 +786,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) = break elif c in {CR, LF, nimlexbase.EndOfFile}: tokenEndIgnore(tok, pos) - lexMessage(L, errClosingQuoteExpected) + lexMessage(L, errGenerated, "closing \" expected") break elif (c == '\\') and not rawMode: L.bufpos = pos @@ -800,12 +802,13 @@ proc getCharacter(L: var TLexer, tok: var TToken) = inc(L.bufpos) # skip ' var c = L.buf[L.bufpos] case c - of '\0'..pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant) + of '\0'..pred(' '), '\'': lexMessage(L, errGenerated, "invalid character literal") of '\\': getEscapedChar(L, tok) else: tok.literal = $c inc(L.bufpos) - if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote) + if L.buf[L.bufpos] != '\'': + lexMessage(L, errGenerated, "missing closing ' for character literal") tokenEndIgnore(tok, L.bufpos) inc(L.bufpos) # skip ' @@ -826,7 +829,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) = inc(pos) of '_': if buf[pos+1] notin SymChars: - lexMessage(L, errInvalidToken, "_") + lexMessage(L, errGenerated, "invalid token: trailing underscore") break inc(pos) else: break @@ -1014,7 +1017,7 @@ proc skip(L: var TLexer, tok: var TToken) = inc(pos) inc(tok.strongSpaceA) of '\t': - if not L.allowTabs: lexMessagePos(L, errTabulatorsAreNotAllowed, pos) + if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabulators are not allowed") inc(pos) of CR, LF: tokenEndPrevious(tok, pos) @@ -1182,7 +1185,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = else: tok.literal = $c tok.tokType = tkInvalid - lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')') + lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')') of '\"': # check for extended raw string literal: var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars @@ -1199,7 +1202,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = getNumber(L, tok) let c = L.buf[L.bufpos] if c in SymChars+{'_'}: - lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')') + lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier") else: if c in OpChars: getOperator(L, tok) @@ -1209,6 +1212,6 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = else: tok.literal = $c tok.tokType = tkInvalid - lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')') + lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')') inc(L.bufpos) atTokenEnd() diff --git a/compiler/msgs.nim b/compiler/msgs.nim index b6cd05e064..08be515d13 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -8,481 +8,13 @@ # import - options, strutils, os, tables, ropes, platform, terminal, macros + options, strutils, os, tables, ropes, platform, terminal, macros, + configuration -const - explanationsBaseUrl* = "https://nim-lang.org/docs/manual" +#type +# MsgConfig* = ref object of RootObj type - TMsgKind* = enum - errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated, - errStringLiteralExpected, - errIntLiteralExpected, errInvalidCharacterConstant, - errClosingTripleQuoteExpected, errClosingQuoteExpected, - errTabulatorsAreNotAllowed, errInvalidToken, - errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange, - errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote, - errIdentifierExpected, errNewlineExpected, errInvalidModuleName, - errOperatorExpected, errTokenExpected, - errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected, - errInvalidPragma, errUnknownPragma, errInvalidDirectiveX, - errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation, - errExceptionAlreadyHandled, - errYieldNotAllowedHere, errYieldNotAllowedInTryStmt, - errInvalidNumberOfYieldExpr, errCannotReturnExpr, - errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine, - errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel, - errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected, - errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler, - errOnOrOffExpectedButXFound, errOnOffOrListExpectedButXFound, - errNoneBoehmRefcExpectedButXFound, - errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound, - errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound, - errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected, - errExprExpected, errUndeclaredField, - errUndeclaredRoutine, errUseQualifier, - errTypeExpected, - errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable, - errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue, - errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous, - errConstantDivisionByZero, errOrdinalTypeExpected, - errOrdinalOrFloatTypeExpected, errOverOrUnderflow, - errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255, - errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess, - errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, - errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit, - errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType, - errCastNotInSafeMode, errExprCannotBeCastToX, errCommaOrParRiExpected, - errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected, - errMagicOnlyInSystem, errPowerOfTwoExpected, - errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv, - errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected, - errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes, - errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid, - errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop, - errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue, - errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig, - errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects, - errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX, - errCannotInstantiateX, errExprHasNoAddress, errXStackEscape, - errVarForOutParamNeededX, - errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, - errAmbiguousCallXYZ, errWrongNumberOfArguments, - errWrongNumberOfArgumentsInCall, - errMissingGenericParamsForTemplate, - errXCannotBePassedToProcVar, - errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed, - errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, - errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, - errInvalidOrderInArrayConstructor, - errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, - errOptionExpected, errXisNoLabel, errNotAllCasesCovered, - errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, - errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, - errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, - errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, - errXNotAllowedHere, errInvalidControlFlowX, - errXisNoType, errCircumNeedsPointer, errInvalidExpression, - errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected, - errNamedExprNotAllowed, errXExpectsOneTypeParam, - errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed, - errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType, - errNoReturnTypeDeclared, - errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope, - errXNeedsParamObjectType, - errTemplateInstantiationTooNested, errMacroInstantiationTooNested, - errInstantiationFrom, - errInvalidIndexValueForTuple, errCommandExpectsFilename, - errMainModuleMustBeSpecified, - errXExpected, - errTIsNotAConcreteType, - errCastToANonConcreteType, - errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, - errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, - errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly, - errOnlyACallOpCanBeDelegator, errUsingNoSymbol, - errMacroBodyDependsOnGenericTypes, - errDestructorNotGenericEnough, - errInlineIteratorsAsProcParams, - errXExpectsTwoArguments, - errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, - errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX, - errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument, - errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate, - errXhasSideEffects, errIteratorExpected, errLetNeedsInit, - errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX, - errXCannotBeClosure, errXMustBeCompileTime, - errCannotInferTypeOfTheLiteral, - errCannotInferReturnType, - errCannotInferStaticParam, - errGenericLambdaNotAllowed, - errProcHasNoConcreteType, - errCompilerDoesntSupportTarget, - errInOutFlagNotExtern, - errUser, - warnCannotOpenFile, - warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, - warnDeprecated, warnConfigDeprecated, - warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, - warnUnknownSubstitutionX, warnLanguageXNotSupported, - warnFieldXNotSupported, warnCommentXIgnored, - warnTypelessParam, - warnUseBase, warnWriteToForeignHeap, warnUnsafeCode, - warnEachIdentIsTuple, warnShadowIdent, - warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, - warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, - warnInconsistentSpacing, warnUser, - hintSuccess, hintSuccessX, - hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, - hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, - hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, - hintConditionAlwaysTrue, hintName, hintPattern, - hintExecuting, hintLinking, hintDependency, - hintSource, hintPerformance, hintStackTrace, hintGCStats, - hintUser, hintUserRaw - -const - MsgKindToStr*: array[TMsgKind, string] = [ - errUnknown: "unknown error", - errInternal: "internal error: $1", - errIllFormedAstX: "illformed AST: $1", - errCannotOpenFile: "cannot open '$1'", - errGenerated: "$1", - errStringLiteralExpected: "string literal expected", - errIntLiteralExpected: "integer literal expected", - errInvalidCharacterConstant: "invalid character constant", - errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached", - errClosingQuoteExpected: "closing \" expected", - errTabulatorsAreNotAllowed: "tabulators are not allowed", - errInvalidToken: "invalid token: $1", - errInvalidNumber: "$1 is not a valid number", - errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.", - errNumberOutOfRange: "number $1 out of valid range", - errNnotAllowedInCharacter: "\\n not allowed in character literal", - errClosingBracketExpected: "closing ']' expected, but end of file reached", - errMissingFinalQuote: "missing final ' for character literal", - errIdentifierExpected: "identifier expected, but found '$1'", - errNewlineExpected: "newline expected, but found '$1'", - errInvalidModuleName: "invalid module name: '$1'", - errOperatorExpected: "operator expected, but found '$1'", - errTokenExpected: "'$1' expected", - errRecursiveDependencyX: "recursive dependency: '$1'", - errOnOrOffExpected: "'on' or 'off' expected", - errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected", - errInvalidPragma: "invalid pragma", - errUnknownPragma: "unknown pragma: '$1'", - errInvalidDirectiveX: "invalid directive: '$1'", - errAtPopWithoutPush: "'pop' without a 'push' pragma", - errEmptyAsm: "empty asm statement", - errInvalidIndentation: "invalid indentation", - errExceptionAlreadyHandled: "exception already handled", - errYieldNotAllowedHere: "'yield' only allowed in an iterator", - errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator", - errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions", - errCannotReturnExpr: "current routine cannot return an expression", - errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type", - errAttemptToRedefine: "redefinition of '$1'", - errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma", - errStmtExpected: "statement expected", - errInvalidLabel: "'$1' is no label", - errInvalidCmdLineOption: "invalid command line option: '$1'", - errCmdLineArgExpected: "argument for command line option expected: '$1'", - errCmdLineNoArgExpected: "invalid argument for command line option: '$1'", - errInvalidVarSubstitution: "invalid variable substitution in '$1'", - errUnknownVar: "unknown variable: '$1'", - errUnknownCcompiler: "unknown C compiler: '$1'", - errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found", - errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found", - errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found", - errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found", - errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found", - errUnknownOS: "unknown OS: '$1'", - errUnknownCPU: "unknown CPU: '$1'", - errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found", - errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected", - errInvalidMultipleAsgn: "multiple assignment is not allowed", - errColonOrEqualsExpected: "':' or '=' expected, but found '$1'", - errExprExpected: "expression expected, but found '$1'", - errUndeclaredField: "undeclared field: '$1'", - errUndeclaredRoutine: "attempting to call undeclared routine: '$1'", - errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier", - errTypeExpected: "type expected", - errSystemNeeds: "system module needs '$1'", - errExecutionOfProgramFailed: "execution of an external program failed: '$1'", - errNotOverloadable: "overloaded '$1' leads to ambiguous calls", - errInvalidArgForX: "invalid argument for '$1'", - errStmtHasNoEffect: "statement has no effect", - errXExpectsTypeOrValue: "'$1' expects a type or value", - errXExpectsArrayType: "'$1' expects an array type", - errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", - errExprXAmbiguous: "expression '$1' ambiguous in this context", - errConstantDivisionByZero: "division by zero", - errOrdinalTypeExpected: "ordinal type expected", - errOrdinalOrFloatTypeExpected: "ordinal or float type expected", - errOverOrUnderflow: "over- or underflow", - errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely", - errChrExpectsRange0_255: "'chr' expects an int in the range 0..255", - errDynlibRequiresExportc: "'dynlib' requires 'exportc'", - errUndeclaredFieldX: "undeclared field: '$1'", - errNilAccess: "attempt to access a nil address", - errIndexOutOfBounds: "index out of bounds", - errIndexTypesDoNotMatch: "index types do not match", - errBracketsInvalidForType: "'[]' operator invalid for this type", - errValueOutOfSetBounds: "value out of set bounds", - errFieldInitTwice: "field initialized twice: '$1'", - errFieldNotInit: "field '$1' not initialized", - errExprXCannotBeCalled: "expression '$1' cannot be called", - errExprHasNoType: "expression has no type", - errExprXHasNoType: "expression '$1' has no type (or is ambiguous)", - errCastNotInSafeMode: "'cast' not allowed in safe mode", - errExprCannotBeCastToX: "expression cannot be cast to $1", - errCommaOrParRiExpected: "',' or ')' expected", - errCurlyLeOrParLeExpected: "'{' or '(' expected", - errSectionExpected: "section ('type', 'proc', etc.) expected", - errRangeExpected: "range expected", - errMagicOnlyInSystem: "'magic' only allowed in system module", - errPowerOfTwoExpected: "power of two expected", - errStringMayNotBeEmpty: "string literal may not be empty", - errCallConvExpected: "calling convention expected", - errProcOnlyOneCallConv: "a proc can only have one calling convention", - errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used", - errExprMustBeBool: "expression must be of type 'bool'", - errConstExprExpected: "constant expression expected", - errDuplicateCaseLabel: "duplicate case label", - errRangeIsEmpty: "range is empty", - errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string", - errSelectorMustBeOrdinal: "selector must be of an ordinal type", - errOrdXMustNotBeNegative: "ord($1) must not be negative", - errLenXinvalid: "len($1) must be less than 32768", - errWrongNumberOfVariables: "wrong number of variables", - errExprCannotBeRaised: "only a 'ref object' can be raised", - errBreakOnlyInLoop: "'break' only allowed in loop construct", - errTypeXhasUnknownSize: "type '$1' has unknown size", - errConstNeedsConstExpr: "a constant can only be initialized with a constant expression", - errConstNeedsValue: "a constant needs a value", - errResultCannotBeOpenArray: "the result type cannot be on open array", - errSizeTooBig: "computing the type's size produced an overflow", - errSetTooBig: "set is too large", - errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal", - errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects", - errInheritanceOnlyWithEnums: "inheritance only works with an enum", - errIllegalRecursionInTypeX: "illegal recursion in type '$1'", - errCannotInstantiateX: "cannot instantiate: '$1'", - errExprHasNoAddress: "expression has no address", - errXStackEscape: "address of '$1' may not escape its stack frame", - errVarForOutParamNeededX: "for a 'var' type a variable needs to be passed; but '$1' is immutable", - errPureTypeMismatch: "type mismatch", - errTypeMismatch: "type mismatch: got <", - errButExpected: "but expected one of: ", - errButExpectedX: "but expected '$1'", - errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3", - errWrongNumberOfArguments: "wrong number of arguments", - errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", - errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", - errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar", - errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", - errImplOfXNotAllowed: "implementation of '$1' is not allowed", - errImplOfXexpected: "implementation of '$1' expected", - errNoSymbolToBorrowFromFound: "no symbol to borrow from found", - errDiscardValueX: "value of type '$1' has to be discarded", - errInvalidDiscard: "statement returns no value that can be discarded", - errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid", - errCannotBindXTwice: "cannot bind parameter '$1' twice", - errInvalidOrderInArrayConstructor: "invalid order in array constructor", - errInvalidOrderInEnumX: "invalid order in enum '$1'", - errEnumXHasHoles: "enum '$1' has holes", - errExceptExpected: "'except' or 'finally' expected", - errInvalidTry: "after catch all 'except' or 'finally' no section may follow", - errOptionExpected: "option expected, but found '$1'", - errXisNoLabel: "'$1' is not a label", - errNotAllCasesCovered: "not all cases are covered", - errUnknownSubstitionVar: "unknown substitution variable: '$1'", - errComplexStmtRequiresInd: "complex statement requires indentation", - errXisNotCallable: "'$1' is not callable", - errNoPragmasAllowedForX: "no pragmas allowed for $1", - errNoGenericParamsAllowedForX: "no generic parameters allowed for $1", - errInvalidParamKindX: "invalid param kind: '$1'", - errDefaultArgumentInvalid: "default argument invalid", - errNamedParamHasToBeIdent: "named parameter has to be an identifier", - errNoReturnTypeForX: "no return type allowed for $1", - errConvNeedsOneArg: "a type conversion needs exactly one argument", - errInvalidPragmaX: "invalid pragma: $1", - errXNotAllowedHere: "$1 not allowed here", - errInvalidControlFlowX: "invalid control flow: $1", - errXisNoType: "invalid type: '$1'", - errCircumNeedsPointer: "'[]' needs a pointer or reference type", - errInvalidExpression: "invalid expression", - errInvalidExpressionX: "invalid expression: '$1'", - errEnumHasNoValueX: "enum has no value '$1'", - errNamedExprExpected: "named expression expected", - errNamedExprNotAllowed: "named expression not allowed here", - errXExpectsOneTypeParam: "'$1' expects one type parameter", - errArrayExpectsTwoTypeParams: "array expects two type parameters", - errInvalidVisibilityX: "invalid visibility: '$1'", - errInitHereNotAllowed: "initialization not allowed here", - errXCannotBeAssignedTo: "'$1' cannot be assigned to", - errIteratorNotAllowed: "iterators can only be defined at the module's top level", - errXNeedsReturnType: "$1 needs a return type", - errNoReturnTypeDeclared: "no return type declared", - errNoCommand: "no command given", - errInvalidCommandX: "invalid command: '$1'", - errXOnlyAtModuleScope: "'$1' is only allowed at top level", - errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", - errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N", - errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N", - errInstantiationFrom: "template/generic instantiation from here", - errInvalidIndexValueForTuple: "invalid index value for tuple subscript", - errCommandExpectsFilename: "command expects a filename argument", - errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", - errXExpected: "'$1' expected", - errTIsNotAConcreteType: "'$1' is not a concrete type.", - errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'", - errInvalidSectionStart: "invalid section start", - errGridTableNotImplemented: "grid table is not implemented", - errGeneralParseError: "general parse error", - errNewSectionExpected: "new section expected", - errWhitespaceExpected: "whitespace expected, got '$1'", - errXisNoValidIndexFile: "'$1' is no valid index file", - errCannotRenderX: "cannot render reStructuredText element '$1'", - errVarVarTypeNotAllowed: "type 'var var' is not allowed", - errInstantiateXExplicitly: "instantiate '$1' explicitly", - errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", - errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", - errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " & - "because the parameter '$1' has a generic type", - errDestructorNotGenericEnough: "Destructor signature is too specific. " & - "A destructor must be associated will all instantiations of a generic type", - errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " & - "templates, macros and other inline iterators", - errXExpectsTwoArguments: "'$1' expects two arguments", - errXExpectsObjectTypes: "'$1' expects object types", - errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype", - errTooManyIterations: "interpretation requires too many iterations; " & - "if you are sure this is not a bug in your code edit " & - "compiler/vmdef.MaxLoopIterations and rebuild the compiler", - errCannotInterpretNodeX: "cannot evaluate '$1'", - errFieldXNotFound: "field '$1' cannot be found", - errInvalidConversionFromTypeX: "invalid conversion from type '$1'", - errAssertionFailed: "assertion failed", - errCannotGenerateCodeForX: "cannot generate code for '$1'", - errXRequiresOneArgument: "$1 requires one parameter", - errUnhandledExceptionX: "unhandled exception: $1", - errCyclicTree: "macro returned a cyclic abstract syntax tree", - errXisNoMacroOrTemplate: "'$1' is no macro or template", - errXhasSideEffects: "'$1' can have side effects", - errIteratorExpected: "iterator within for loop context expected", - errLetNeedsInit: "'let' symbol requires an initialization", - errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread", - errWrongSymbolX: "usage of '$1' is a user-defined error", - errIllegalCaptureX: "illegal capture '$1'", - errXCannotBeClosure: "'$1' cannot have 'closure' calling convention", - errXMustBeCompileTime: "'$1' can only be used in compile-time context", - errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1", - errCannotInferReturnType: "cannot infer the return type of the proc", - errCannotInferStaticParam: "cannot infer the value of the static param `$1`", - errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " & - "it is used as an operand to another routine and the types " & - "of the generic paramers can be inferred from the expected signature.", - errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.", - errCompilerDoesntSupportTarget: "The current compiler '$1' doesn't support the requested compilation target", - errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types", - errUser: "$1", - warnCannotOpenFile: "cannot open '$1'", - warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored", - warnXIsNeverRead: "'$1' is never read", - warnXmightNotBeenInit: "'$1' might not have been initialized", - warnDeprecated: "$1 is deprecated", - warnConfigDeprecated: "config file '$1' is deprecated", - warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)", - warnUnknownMagic: "unknown magic '$1' might crash the compiler", - warnRedefinitionOfLabel: "redefinition of label '$1'", - warnUnknownSubstitutionX: "unknown substitution '$1'", - warnLanguageXNotSupported: "language '$1' not supported", - warnFieldXNotSupported: "field '$1' not supported", - warnCommentXIgnored: "comment '$1' ignored", - warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'", - warnUseBase: "use {.base.} for base methods; baseless methods are deprecated", - warnWriteToForeignHeap: "write to foreign heap", - warnUnsafeCode: "unsafe code: '$1'", - warnEachIdentIsTuple: "each identifier is a tuple", - warnShadowIdent: "shadowed identifier: '$1'", - warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.", - warnProveField: "cannot prove that field '$1' is accessible", - warnProveIndex: "cannot prove index '$1' is valid", - warnGcUnsafe: "not GC-safe: '$1'", - warnGcUnsafe2: "$1", - warnUninit: "'$1' might not have been initialized", - warnGcMem: "'$1' uses GC'ed memory", - warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.", - warnLockLevel: "$1", - warnResultShadowed: "Special variable 'result' is shadowed.", - warnInconsistentSpacing: "Number of spaces around '$#' is not consistent", - warnUser: "$1", - hintSuccess: "operation successful", - hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", - hintLineTooLong: "line too long", - hintXDeclaredButNotUsed: "'$1' is declared but not used", - hintConvToBaseNotNeeded: "conversion to base object is not needed", - hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless", - hintExprAlwaysX: "expression evaluates always to '$1'", - hintQuitCalled: "quit() called", - hintProcessing: "$1", - hintCodeBegin: "generated code listing:", - hintCodeEnd: "end of listing", - hintConf: "used config file '$1'", - hintPath: "added path: '$1'", - hintConditionAlwaysTrue: "condition is always true: '$1'", - hintName: "name should be: '$1'", - hintPattern: "$1", - hintExecuting: "$1", - hintLinking: "", - hintDependency: "$1", - hintSource: "$1", - hintPerformance: "$1", - hintStackTrace: "$1", - hintGCStats: "$1", - hintUser: "$1", - hintUserRaw: "$1"] - -const - WarningsToStr* = ["CannotOpenFile", "OctalEscape", - "XIsNeverRead", "XmightNotBeenInit", - "Deprecated", "ConfigDeprecated", - "SmallLshouldNotBeUsed", "UnknownMagic", - "RedefinitionOfLabel", "UnknownSubstitutionX", - "LanguageXNotSupported", "FieldXNotSupported", - "CommentXIgnored", - "TypelessParam", "UseBase", "WriteToForeignHeap", - "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", - "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", - "GcMem", "Destructor", "LockLevel", "ResultShadowed", - "Spacing", "User"] - - HintsToStr* = ["Success", "SuccessX", "LineTooLong", - "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", - "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", - "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency", - "Source", "Performance", "StackTrace", "GCStats", - "User", "UserRaw"] - -const - fatalMin* = errUnknown - fatalMax* = errInternal - errMin* = errUnknown - errMax* = errUser - warnMin* = warnCannotOpenFile - warnMax* = pred(hintSuccess) - hintMin* = hintSuccess - hintMax* = high(TMsgKind) - -static: - doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1 - doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1 - -type - TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints - TNoteKinds* = set[TNoteKind] - TFileInfo* = object fullPath: string # This is a canonical full filesystem path projPath*: string # This is relative to the project's root @@ -527,35 +59,11 @@ type proc `==`*(a, b: FileIndex): bool {.borrow.} -const - NotesVerbosity*: array[0..3, TNoteKinds] = [ - {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit, - warnProveField, warnProveIndex, - warnGcUnsafe, - hintSuccessX, hintPath, hintConf, - hintProcessing, hintPattern, - hintDependency, - hintExecuting, hintLinking, - hintCodeBegin, hintCodeEnd, - hintSource, hintStackTrace, - hintGCStats}, - {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit, - warnProveField, warnProveIndex, - warnGcUnsafe, - hintPath, - hintDependency, - hintCodeBegin, hintCodeEnd, - hintSource, hintStackTrace, - hintGCStats}, - {low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit}, - {low(TNoteKind)..high(TNoteKind)}] const InvalidFileIDX* = FileIndex(-1) var - ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic, - hintQuitCalled, hintExecuting} filenameToIndexTbl = initTable[string, FileIndex]() fileInfos*: seq[TFileInfo] = @[] systemFileIdx*: FileIndex @@ -606,22 +114,22 @@ when defined(nimpretty): proc fileSection*(fid: FileIndex; a, b: int): string = substr(fileInfos[fid.int].fullContent, a, b) -proc fileInfoKnown*(filename: string): bool = +proc fileInfoKnown*(conf: ConfigRef; filename: string): bool = var canon: string try: - canon = canonicalizePath(filename) + canon = canonicalizePath(conf, filename) except: canon = filename result = filenameToIndexTbl.hasKey(canon) -proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex = +proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex = var canon: string pseudoPath = false try: - canon = canonicalizePath(filename) + canon = canonicalizePath(conf, filename) shallow(canon) except: canon = filename @@ -635,40 +143,33 @@ proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex = isKnownFile = false result = fileInfos.len.FileIndex fileInfos.add(newFileInfo(canon, if pseudoPath: filename - else: canon.shortenDir)) + else: shortenDir(conf, canon))) filenameToIndexTbl[canon] = result -proc fileInfoIdx*(filename: string): FileIndex = +proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex = var dummy: bool - result = fileInfoIdx(filename, dummy) + result = fileInfoIdx(conf, filename, dummy) proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo = result.fileIndex = fileInfoIdx result.line = uint16(line) result.col = int16(col) -proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} = - result = newLineInfo(filename.fileInfoIdx, line, col) +proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} = + result = newLineInfo(fileInfoIdx(conf, filename), line, col) -fileInfos.add(newFileInfo("", "command line")) -var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1) +when false: + fileInfos.add(newFileInfo("", "command line")) + var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1) -fileInfos.add(newFileInfo("", "compilation artifact")) -var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1) + fileInfos.add(newFileInfo("", "compilation artifact")) + var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1) proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} = raise newException(ERecoverableError, msg) proc sourceLine*(i: TLineInfo): Rope -var - gNotes*: TNoteKinds = NotesVerbosity[1] # defaults to verbosity of 1 - gErrorCounter*: int = 0 # counts the number of errors - gHintCounter*: int = 0 - gWarnCounter*: int = 0 - gErrorMax*: int = 1 # stop after gErrorMax errors - gMainPackageNotes*: TNoteKinds = NotesVerbosity[1] - proc unknownLineInfo*(): TLineInfo = result.line = uint16(0) result.col = int16(-1) @@ -892,8 +393,8 @@ proc log*(s: string) {.procvar.} = f.writeLine(s) close(f) -proc quit(msg: TMsgKind) = - if defined(debug) or msg == errInternal or hintStackTrace in gNotes: +proc quit(conf: ConfigRef; msg: TMsgKind) = + if defined(debug) or msg == errInternal or hintStackTrace in conf.notes: if stackTraceAvailable() and isNil(writelnHook): writeStackTrace() else: @@ -902,17 +403,17 @@ proc quit(msg: TMsgKind) = options.command & " ") quit 1 -proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = +proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) = if msg >= fatalMin and msg <= fatalMax: if gCmd == cmdIdeTools: log(s) - quit(msg) + quit(conf, msg) if msg >= errMin and msg <= errMax: - inc(gErrorCounter) + inc(conf.errorCounter) options.gExitcode = 1'i8 - if gErrorCounter >= gErrorMax: - quit(msg) + if conf.errorCounter >= conf.errorMax: + quit(conf, msg) elif eh == doAbort and gCmd != cmdIdeTools: - quit(msg) + quit(conf, msg) elif eh == doRaise: raiseRecoverableError(s) @@ -922,12 +423,13 @@ proc `==`*(a, b: TLineInfo): bool = proc exactEquals*(a, b: TLineInfo): bool = result = a.fileIndex == b.fileIndex and a.line == b.line and a.col == b.col -proc writeContext(lastinfo: TLineInfo) = +proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) = + const instantiationFrom = "template/generic instantiation from here" var info = lastinfo for i in countup(0, len(msgContext) - 1): if msgContext[i] != lastinfo and msgContext[i] != info: if structuredErrorHook != nil: - structuredErrorHook(msgContext[i], getMessageStr(errInstantiationFrom, ""), + structuredErrorHook(msgContext[i], instantiationFrom, Severity.Error) else: styledMsgWriteln(styleBright, @@ -935,13 +437,13 @@ proc writeContext(lastinfo: TLineInfo) = coordToStr(msgContext[i].line.int), coordToStr(msgContext[i].col+1)], resetStyle, - getMessageStr(errInstantiationFrom, "")) + instantiationFrom) info = msgContext[i] -proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool = +proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool = msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions -proc rawMessage*(msg: TMsgKind, args: openArray[string]) = +proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = var title: string color: ForegroundColor @@ -950,43 +452,43 @@ proc rawMessage*(msg: TMsgKind, args: openArray[string]) = case msg of errMin..errMax: sev = Severity.Error - writeContext(unknownLineInfo()) + writeContext(conf, unknownLineInfo()) title = ErrorTitle color = ErrorColor of warnMin..warnMax: sev = Severity.Warning if optWarns notin gOptions: return - if msg notin gNotes: return - writeContext(unknownLineInfo()) + if msg notin conf.notes: return + writeContext(conf, unknownLineInfo()) title = WarningTitle color = WarningColor kind = WarningsToStr[ord(msg) - ord(warnMin)] - inc(gWarnCounter) + inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint if optHints notin gOptions: return - if msg notin gNotes: return + if msg notin conf.notes: return title = HintTitle color = HintColor if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] - inc(gHintCounter) + inc(conf.hintCounter) let s = msgKindToString(msg) % args if structuredErrorHook != nil: structuredErrorHook(unknownLineInfo(), s & (if kind != nil: KindFormat % kind else: ""), sev) - if not ignoreMsgBecauseOfIdeTools(msg): + if not ignoreMsgBecauseOfIdeTools(conf, msg): if kind != nil: styledMsgWriteln(color, title, resetStyle, s, KindColor, `%`(KindFormat, kind)) else: styledMsgWriteln(color, title, resetStyle, s) - handleError(msg, doAbort, s) + handleError(conf, msg, doAbort, s) -proc rawMessage*(msg: TMsgKind, arg: string) = - rawMessage(msg, [arg]) +proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) = + rawMessage(conf, msg, [arg]) -proc resetAttributes* = +proc resetAttributes*(conf: ConfigRef) = if {optUseColors, optStdout} * gGlobalOptions == {optUseColors}: terminal.resetAttributes(stderr) @@ -1005,7 +507,7 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string = title & getMessageStr(msg, arg) -proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, +proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, eh: TErrorHandling) = var title: string @@ -1016,7 +518,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, case msg of errMin..errMax: sev = Severity.Error - writeContext(info) + writeContext(conf, info) title = ErrorTitle color = ErrorColor # we try to filter error messages so that not two error message @@ -1025,19 +527,19 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, lastError = info of warnMin..warnMax: sev = Severity.Warning - ignoreMsg = optWarns notin gOptions or msg notin gNotes - if not ignoreMsg: writeContext(info) + ignoreMsg = optWarns notin gOptions or msg notin conf.notes + if not ignoreMsg: writeContext(conf, info) title = WarningTitle color = WarningColor kind = WarningsToStr[ord(msg) - ord(warnMin)] - inc(gWarnCounter) + inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint - ignoreMsg = optHints notin gOptions or msg notin gNotes + ignoreMsg = optHints notin gOptions or msg notin conf.notes title = HintTitle color = HintColor if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] - inc(gHintCounter) + inc(conf.hintCounter) # NOTE: currently line info line numbers start with 1, # but column numbers start with 0, however most editors expect # first column to be 1, so we need to +1 here @@ -1048,56 +550,56 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, if not ignoreMsg: if structuredErrorHook != nil: structuredErrorHook(info, s & (if kind != nil: KindFormat % kind else: ""), sev) - if not ignoreMsgBecauseOfIdeTools(msg): + if not ignoreMsgBecauseOfIdeTools(conf, msg): if kind != nil: styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s, KindColor, `%`(KindFormat, kind)) else: styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s) - if hintSource in gNotes: - info.writeSurroundingSrc - handleError(msg, eh, s) + if hintSource in conf.notes: + info.writeSurroundingSrc() + handleError(conf, msg, eh, s) -proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") = +proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = # this fixes bug #7080 so that it is at least obvious 'fatal' # was executed. errorOutputs = {eStdOut, eStdErr} - liMessage(info, msg, arg, doAbort) + liMessage(conf, info, msg, arg, doAbort) -proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") = - liMessage(info, msg, arg, doRaise) +proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = + liMessage(conf, info, msg, arg, doRaise) -proc globalError*(info: TLineInfo, arg: string) = - liMessage(info, errGenerated, arg, doRaise) +proc globalError*(conf: ConfigRef; info: TLineInfo, arg: string) = + liMessage(conf, info, errGenerated, arg, doRaise) -proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") = - liMessage(info, msg, arg, doNothing) +proc localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = + liMessage(conf, info, msg, arg, doNothing) -proc localError*(info: TLineInfo, arg: string) = - liMessage(info, errGenerated, arg, doNothing) +proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) = + liMessage(conf, info, errGenerated, arg, doNothing) -proc localError*(info: TLineInfo, format: string, params: openarray[string]) = - localError(info, format % params) +proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openarray[string]) = + localError(conf, info, format % params) -proc message*(info: TLineInfo, msg: TMsgKind, arg = "") = - liMessage(info, msg, arg, doNothing) +proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = + liMessage(conf, info, msg, arg, doNothing) -proc internalError*(info: TLineInfo, errMsg: string) = +proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) = if gCmd == cmdIdeTools and structuredErrorHook.isNil: return - writeContext(info) - liMessage(info, errInternal, errMsg, doAbort) + writeContext(conf, info) + liMessage(conf, info, errInternal, errMsg, doAbort) -proc internalError*(errMsg: string) = +proc internalError*(conf: ConfigRef; errMsg: string) = if gCmd == cmdIdeTools and structuredErrorHook.isNil: return - writeContext(unknownLineInfo()) - rawMessage(errInternal, errMsg) + writeContext(conf, unknownLineInfo()) + rawMessage(conf, errInternal, errMsg) -template assertNotNil*(e): untyped = - if e == nil: internalError($instantiationInfo()) +template assertNotNil*(conf, e): untyped = + if e == nil: internalError(conf, $instantiationInfo()) e -template internalAssert*(e: bool) = - if not e: internalError($instantiationInfo()) +template internalAssert*(conf, e: bool) = + if not e: internalError(conf, $instantiationInfo()) proc addSourceLine*(fileIdx: FileIndex, line: string) = fileInfos[fileIdx.int32].lines.add line.rope @@ -1111,14 +613,14 @@ proc sourceLine*(i: TLineInfo): Rope = addSourceLine i.fileIndex, line.string except IOError: discard - internalAssert i.fileIndex.int32 < fileInfos.len + assert i.fileIndex.int32 < fileInfos.len # can happen if the error points to EOF: if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil result = fileInfos[i.fileIndex.int32].lines[i.line.int-1] proc quotedFilename*(i: TLineInfo): Rope = - internalAssert i.fileIndex.int32 >= 0 + assert i.fileIndex.int32 >= 0 if optExcessiveStackTrace in gGlobalOptions: result = fileInfos[i.fileIndex.int32].quotedFullName else: @@ -1127,24 +629,24 @@ proc quotedFilename*(i: TLineInfo): Rope = ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) = case err of rInvalidFormatStr: - internalError("ropes: invalid format string: " & msg) + internalError(newConfigRef(), "ropes: invalid format string: " & msg) of rCannotOpenFile: - rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg) + rawMessage(newConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg) -proc listWarnings*() = +proc listWarnings*(conf: ConfigRef) = msgWriteln("Warnings:") for warn in warnMin..warnMax: msgWriteln(" [$1] $2" % [ - if warn in gNotes: "x" else: " ", - msgs.WarningsToStr[ord(warn) - ord(warnMin)] + if warn in conf.notes: "x" else: " ", + configuration.WarningsToStr[ord(warn) - ord(warnMin)] ]) -proc listHints*() = +proc listHints*(conf: ConfigRef) = msgWriteln("Hints:") for hint in hintMin..hintMax: msgWriteln(" [$1] $2" % [ - if hint in gNotes: "x" else: " ", - msgs.HintsToStr[ord(hint) - ord(hintMin)] + if hint in conf.notes: "x" else: " ", + configuration.HintsToStr[ord(hint) - ord(hintMin)] ]) # enable colors by default on terminals diff --git a/compiler/nim.nim b/compiler/nim.nim index 2807823303..b39eefd650 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -39,7 +39,7 @@ proc prependCurDir(f: string): string = proc handleCmdLine(cache: IdentCache; config: ConfigRef) = if paramCount() == 0: - writeCommandLineUsage() + writeCommandLineUsage(config.helpWritten) else: # Process command line arguments: processCmdLine(passCmd1, "", config) diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 0f9e03352b..da83e94999 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -9,9 +9,10 @@ ## Implements some helper procs for Nimble (Nim's package manager) support. -import parseutils, strutils, strtabs, os, options, msgs, sequtils +import parseutils, strutils, strtabs, os, options, msgs, sequtils, + configuration -proc addPath*(path: string, info: TLineInfo) = +proc addPath*(conf: ConfigRef; path: string, info: TLineInfo) = if not options.searchPaths.contains(path): options.searchPaths.insert(path, 0) @@ -84,7 +85,7 @@ proc getPathVersion*(p: string): tuple[name, version: string] = result.name = p[0 .. sepIdx - 1] result.version = p.substr(sepIdx + 1) -proc addPackage(packages: StringTableRef, p: string; info: TLineInfo) = +proc addPackage(conf: ConfigRef; packages: StringTableRef, p: string; info: TLineInfo) = let (name, ver) = getPathVersion(p) if isValidVersion(ver): let version = newVersion(ver) @@ -92,14 +93,14 @@ proc addPackage(packages: StringTableRef, p: string; info: TLineInfo) = (not packages.hasKey(name)): packages[name] = $version else: - localError(info, "invalid package name: " & p) + localError(conf, info, "invalid package name: " & p) iterator chosen(packages: StringTableRef): string = for key, val in pairs(packages): let res = if val.len == 0: key else: key & '-' & val yield res -proc addNimblePath(p: string, info: TLineInfo) = +proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) = var path = p let nimbleLinks = toSeq(walkPattern(p / "*.nimble-link")) if nimbleLinks.len > 0: @@ -112,22 +113,22 @@ proc addNimblePath(p: string, info: TLineInfo) = path = p / path if not contains(options.searchPaths, path): - message(info, hintPath, path) + message(conf, info, hintPath, path) options.lazyPaths.insert(path, 0) -proc addPathRec(dir: string, info: TLineInfo) = +proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) = var packages = newStringTable(modeStyleInsensitive) var pos = dir.len-1 if dir[pos] in {DirSep, AltSep}: inc(pos) for k,p in os.walkDir(dir): if k == pcDir and p[pos] != '.': - addPackage(packages, p, info) + addPackage(conf, packages, p, info) for p in packages.chosen: - addNimblePath(p, info) + addNimblePath(conf, p, info) -proc nimblePath*(path: string, info: TLineInfo) = - addPathRec(path, info) - addNimblePath(path, info) +proc nimblePath*(conf: ConfigRef; path: string, info: TLineInfo) = + addPathRec(conf, path, info) + addNimblePath(conf, path, info) when isMainModule: proc v(s: string): Version = s.newVersion diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index dc8d082b3d..9f5031d3bd 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -11,7 +11,7 @@ import llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer, - options, idents, wordrecg, strtabs + options, idents, wordrecg, strtabs, configuration # ---------------- configuration file parser ----------------------------- # we use Nim's scanner here to save space and work @@ -27,12 +27,12 @@ proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool = ppGetTok(L, tok) result = parseExpr(L, tok, config) if tok.tokType == tkParRi: ppGetTok(L, tok) - else: lexMessage(L, errTokenExpected, "\')\'") + else: lexMessage(L, errGenerated, "expected closing ')'") elif tok.ident.id == ord(wNot): ppGetTok(L, tok) result = not parseAtom(L, tok, config) else: - result = isDefined(tok.ident) + result = isDefined(config, tok.ident.s) ppGetTok(L, tok) proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool = @@ -53,12 +53,12 @@ proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool = ppGetTok(L, tok) # skip 'if' or 'elif' result = parseExpr(L, tok, config) if tok.tokType == tkColon: ppGetTok(L, tok) - else: lexMessage(L, errTokenExpected, "\':\'") + else: lexMessage(L, errGenerated, "expected ':'") -var condStack: seq[bool] = @[] +#var condStack: seq[bool] = @[] -proc doEnd(L: var TLexer, tok: var TToken) = - if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") +proc doEnd(L: var TLexer, tok: var TToken; condStack: var seq[bool]) = + if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if") ppGetTok(L, tok) # skip 'end' setLen(condStack, high(condStack)) @@ -66,20 +66,22 @@ type TJumpDest = enum jdEndif, jdElseEndif -proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef) -proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) = - if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") +proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef; + condStack: var seq[bool]) +proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) = + if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if") ppGetTok(L, tok) if tok.tokType == tkColon: ppGetTok(L, tok) - if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config) + if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config, condStack) -proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef) = - if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") +proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) = + if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if") var res = evalppIf(L, tok, config) - if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config) + if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config, condStack) else: condStack[high(condStack)] = true -proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef) = +proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef; + condStack: var seq[bool]) = var nestedIfs = 0 while true: if tok.ident != nil and tok.ident.s == "@": @@ -89,36 +91,36 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: Co inc(nestedIfs) of wElse: if dest == jdElseEndif and nestedIfs == 0: - doElse(L, tok, config) + doElse(L, tok, config, condStack) break of wElif: if dest == jdElseEndif and nestedIfs == 0: - doElif(L, tok, config) + doElif(L, tok, config, condStack) break of wEnd: if nestedIfs == 0: - doEnd(L, tok) + doEnd(L, tok, condStack) break if nestedIfs > 0: dec(nestedIfs) else: discard ppGetTok(L, tok) elif tok.tokType == tkEof: - lexMessage(L, errTokenExpected, "@end") + lexMessage(L, errGenerated, "expected @end") else: ppGetTok(L, tok) -proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) = +proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) = ppGetTok(L, tok) # skip @ case whichKeyword(tok.ident) of wIf: setLen(condStack, len(condStack) + 1) let res = evalppIf(L, tok, config) condStack[high(condStack)] = res - if not res: jumpToDirective(L, tok, jdElseEndif, config) - of wElif: doElif(L, tok, config) - of wElse: doElse(L, tok, config) - of wEnd: doEnd(L, tok) + if not res: jumpToDirective(L, tok, jdElseEndif, config, condStack) + of wElif: doElif(L, tok, config, condStack) + of wElse: doElse(L, tok, config, condStack) + of wEnd: doEnd(L, tok, condStack) of wWrite: ppGetTok(L, tok) msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars, @@ -144,53 +146,55 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) = ppGetTok(L, tok) os.putEnv(key, os.getEnv(key) & tokToStr(tok)) ppGetTok(L, tok) - else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok)) + else: + lexMessage(L, errGenerated, "invalid directive: '$1'" % tokToStr(tok)) -proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) = +proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) = ppGetTok(L, tok) while tok.ident != nil and tok.ident.s == "@": - parseDirective(L, tok, config) # else: give the token to the parser + parseDirective(L, tok, config, condStack) # else: give the token to the parser proc checkSymbol(L: TLexer, tok: TToken) = if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}: - lexMessage(L, errIdentifierExpected, tokToStr(tok)) + lexMessage(L, errGenerated, "expected identifier, but got: " & tokToStr(tok)) -proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) = +proc parseAssignment(L: var TLexer, tok: var TToken; + config: ConfigRef; condStack: var seq[bool]) = if tok.ident.s == "-" or tok.ident.s == "--": - confTok(L, tok, config) # skip unnecessary prefix + confTok(L, tok, config, condStack) # skip unnecessary prefix var info = getLineInfo(L, tok) # save for later in case of an error checkSymbol(L, tok) var s = tokToStr(tok) - confTok(L, tok, config) # skip symbol + confTok(L, tok, config, condStack) # skip symbol var val = "" while tok.tokType == tkDot: add(s, '.') - confTok(L, tok, config) + confTok(L, tok, config, condStack) checkSymbol(L, tok) add(s, tokToStr(tok)) - confTok(L, tok, config) + confTok(L, tok, config, condStack) if tok.tokType == tkBracketLe: # BUGFIX: val, not s! # BUGFIX: do not copy '['! - confTok(L, tok, config) + confTok(L, tok, config, condStack) checkSymbol(L, tok) add(val, tokToStr(tok)) - confTok(L, tok, config) - if tok.tokType == tkBracketRi: confTok(L, tok, config) - else: lexMessage(L, errTokenExpected, "']'") + confTok(L, tok, config, condStack) + if tok.tokType == tkBracketRi: confTok(L, tok, config, condStack) + else: lexMessage(L, errGenerated, "expected closing ']'") add(val, ']') let percent = tok.ident != nil and tok.ident.s == "%=" if tok.tokType in {tkColon, tkEquals} or percent: if len(val) > 0: add(val, ':') - confTok(L, tok, config) # skip ':' or '=' or '%' + confTok(L, tok, config, condStack) # skip ':' or '=' or '%' checkSymbol(L, tok) add(val, tokToStr(tok)) - confTok(L, tok, config) # skip symbol + confTok(L, tok, config, condStack) # skip symbol while tok.ident != nil and tok.ident.s == "&": - confTok(L, tok, config) + confTok(L, tok, config, condStack) checkSymbol(L, tok) add(val, tokToStr(tok)) - confTok(L, tok, config) + confTok(L, tok, config, condStack) if percent: processSwitch(s, strtabs.`%`(val, options.gConfigVars, {useEnvironment, useEmpty}), passPP, info, config) @@ -207,34 +211,35 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) = initToken(tok) openLexer(L, filename, stream, cache, config) tok.tokType = tkEof # to avoid a pointless warning - confTok(L, tok, config) # read in the first token - while tok.tokType != tkEof: parseAssignment(L, tok, config) - if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end") + var condStack: seq[bool] = @[] + confTok(L, tok, config, condStack) # read in the first token + while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack) + if len(condStack) > 0: lexMessage(L, errGenerated, "expected @end") closeLexer(L) - rawMessage(hintConf, filename) + rawMessage(config, hintConf, filename) proc getUserConfigPath(filename: string): string = result = joinPath(getConfigDir(), filename) -proc getSystemConfigPath(filename: string): string = +proc getSystemConfigPath(conf: ConfigRef; filename: string): string = # try standard configuration file (installation did not distribute files # the UNIX way) - let p = getPrefixDir() + let p = getPrefixDir(conf) result = joinPath([p, "config", filename]) when defined(unix): if not existsFile(result): result = joinPath([p, "etc", filename]) if not existsFile(result): result = "/etc/" & filename proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) = - setDefaultLibpath() + setDefaultLibpath(config) if optSkipConfigFile notin gGlobalOptions: - readConfigFile(getSystemConfigPath(cfg), cache, config) + readConfigFile(getSystemConfigPath(config, cfg), cache, config) if optSkipUserConfigFile notin gGlobalOptions: readConfigFile(getUserConfigPath(cfg), cache, config) - var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir() + let pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir() if optSkipParentConfigFiles notin gGlobalOptions: for dir in parentDirs(pd, fromRoot=true, inclusive=false): readConfigFile(dir / cfg, cache, config) diff --git a/compiler/options.nim b/compiler/options.nim index fe8be5e0c4..ec87ed805e 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -8,7 +8,7 @@ # import - os, strutils, strtabs, osproc, sets + os, strutils, strtabs, osproc, sets, configuration, platform const hasTinyCBackend* = defined(tinyc) @@ -118,16 +118,71 @@ type features*: set[Feature] arguments*: string ## the arguments to be passed to the program that ## should be run + helpWritten*: bool + enableNotes*: TNoteKinds + disableNotes*: TNoteKinds + foreignPackageNotes*: TNoteKinds + notes*: TNoteKinds + mainPackageNotes*: TNoteKinds + errorCounter*: int + hintCounter*: int + warnCounter*: int + errorMax*: int + symbols*: StringTableRef ## We need to use a StringTableRef here as defined + ## symbols are always guaranteed to be style + ## insensitive. Otherwise hell would break lose. const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} proc newConfigRef*(): ConfigRef = result = ConfigRef(cppDefines: initSet[string](), - headerFile: "", features: {}) + headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic, + hintQuitCalled, hintExecuting}, + notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], + symbols: newStringTable(modeStyleInsensitive)) proc cppDefine*(c: ConfigRef; define: string) = c.cppDefines.incl define +proc isDefined*(conf: ConfigRef; symbol: string): bool = + if conf.symbols.hasKey(symbol): + result = conf.symbols[symbol] != "false" + elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0: + result = true + elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0: + result = true + else: + case symbol.normalize + of "x86": result = targetCPU == cpuI386 + of "itanium": result = targetCPU == cpuIa64 + of "x8664": result = targetCPU == cpuAmd64 + of "posix", "unix": + result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos, + osQnx, osAtari, osAix, + osHaiku, osVxWorks, osSolaris, osNetbsd, + osFreebsd, osOpenbsd, osDragonfly, osMacosx, + osAndroid} + of "linux": + result = targetOS in {osLinux, osAndroid} + of "bsd": + result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly} + of "emulatedthreadvars": + result = platform.OS[targetOS].props.contains(ospLacksThreadVars) + of "msdos": result = targetOS == osDos + of "mswindows", "win32": result = targetOS == osWindows + of "macintosh": result = targetOS in {osMacos, osMacosx} + of "sunos": result = targetOS == osSolaris + of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian + of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian + of "cpu8": result = CPU[targetCPU].bit == 8 + of "cpu16": result = CPU[targetCPU].bit == 16 + of "cpu32": result = CPU[targetCPU].bit == 32 + of "cpu64": result = CPU[targetCPU].bit == 64 + of "nimrawsetjmp": + result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd, + osDragonfly, osMacosx} + else: discard + var gIdeCmd*: IdeCmd gOldNewlines*: bool @@ -226,20 +281,20 @@ proc mainCommandArg*: string = else: result = gProjectName -proc existsConfigVar*(key: string): bool = +proc existsConfigVar*(conf: ConfigRef; key: string): bool = result = hasKey(gConfigVars, key) -proc getConfigVar*(key: string): string = +proc getConfigVar*(conf: ConfigRef; key: string): string = result = gConfigVars.getOrDefault key -proc setConfigVar*(key, val: string) = +proc setConfigVar*(conf: ConfigRef; key, val: string) = gConfigVars[key] = val -proc getOutFile*(filename, ext: string): string = +proc getOutFile*(conf: ConfigRef; filename, ext: string): string = if options.outFile != "": result = options.outFile else: result = changeFileExt(filename, ext) -proc getPrefixDir*(): string = +proc getPrefixDir*(conf: ConfigRef): string = ## Gets the prefix dir, usually the parent directory where the binary resides. ## ## This is overridden by some tools (namely nimsuggest) via the ``gPrefixDir`` @@ -248,11 +303,11 @@ proc getPrefixDir*(): string = else: result = splitPath(getAppDir()).head -proc setDefaultLibpath*() = +proc setDefaultLibpath*(conf: ConfigRef) = # set default value (can be overwritten): if libpath == "": # choose default libpath: - var prefix = getPrefixDir() + var prefix = getPrefixDir(conf) when defined(posix): if prefix == "/usr": libpath = "/usr/lib/nim" elif prefix == "/usr/local": libpath = "/usr/local/lib/nim" @@ -263,12 +318,12 @@ proc setDefaultLibpath*() = # modules and make use of them. let realNimPath = findExe("nim") # Find out if $nim/../../lib/system.nim exists. - let parentNimLibPath = realNimPath.parentDir().parentDir() / "lib" + let parentNimLibPath = realNimPath.parentDir.parentDir / "lib" if not fileExists(libpath / "system.nim") and fileExists(parentNimlibPath / "system.nim"): libpath = parentNimLibPath -proc canonicalizePath*(path: string): string = +proc canonicalizePath*(conf: ConfigRef; path: string): string = # on Windows, 'expandFilename' calls getFullPathName which doesn't do # case corrections, so we have to use this convoluted way of retrieving # the true filename (see tests/modules and Nimble uses 'import Uri' instead @@ -280,12 +335,12 @@ proc canonicalizePath*(path: string): string = else: result = path.expandFilename -proc shortenDir*(dir: string): string = +proc shortenDir*(conf: ConfigRef; dir: string): string = ## returns the interesting part of a dir var prefix = gProjectPath & DirSep if startsWith(dir, prefix): return substr(dir, len(prefix)) - prefix = getPrefixDir() & DirSep + prefix = getPrefixDir(conf) & DirSep if startsWith(dir, prefix): return substr(dir, len(prefix)) result = dir @@ -296,42 +351,42 @@ proc removeTrailingDirSep*(path: string): string = else: result = path -proc disableNimblePath*() = +proc disableNimblePath*(conf: ConfigRef) = gNoNimblePath = true lazyPaths.setLen(0) include packagehandling -proc getNimcacheDir*: string = - result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir / +proc getNimcacheDir*(conf: ConfigRef): string = + result = if nimcacheDir.len > 0: nimcacheDir else: shortenDir(conf, gProjectPath) / genSubDir -proc pathSubs*(p, config: string): string = +proc pathSubs*(conf: ConfigRef; p, config: string): string = let home = removeTrailingDirSep(os.getHomeDir()) result = unixToNativePath(p % [ - "nim", getPrefixDir(), + "nim", getPrefixDir(conf), "lib", libpath, "home", home, "config", config, "projectname", options.gProjectName, "projectpath", options.gProjectPath, "projectdir", options.gProjectPath, - "nimcache", getNimcacheDir()]) + "nimcache", getNimcacheDir(conf)]) if "~/" in result: result = result.replace("~/", home & '/') -proc toGeneratedFile*(path, ext: string): string = +proc toGeneratedFile*(conf: ConfigRef; path, ext: string): string = ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod" var (head, tail) = splitPath(path) #if len(head) > 0: head = shortenDir(head & dirSep) - result = joinPath([getNimcacheDir(), changeFileExt(tail, ext)]) + result = joinPath([getNimcacheDir(conf), changeFileExt(tail, ext)]) #echo "toGeneratedFile(", path, ", ", ext, ") = ", result -proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = +proc completeGeneratedFilePath*(conf: ConfigRef; f: string, createSubDir: bool = true): string = var (head, tail) = splitPath(f) #if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep)) - var subdir = getNimcacheDir() # / head + var subdir = getNimcacheDir(conf) # / head if createSubDir: try: createDir(subdir) @@ -341,14 +396,14 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = result = joinPath(subdir, tail) #echo "completeGeneratedFilePath(", f, ") = ", result -proc rawFindFile(f: string): string = +proc rawFindFile(conf: ConfigRef; f: string): string = for it in searchPaths: result = joinPath(it, f) if existsFile(result): - return result.canonicalizePath + return canonicalizePath(conf, result) result = "" -proc rawFindFile2(f: string): string = +proc rawFindFile2(conf: ConfigRef; f: string): string = for i, it in lazyPaths: result = joinPath(it, f) if existsFile(result): @@ -356,30 +411,30 @@ proc rawFindFile2(f: string): string = for j in countDown(i,1): swap(lazyPaths[j], lazyPaths[j-1]) - return result.canonicalizePath + return canonicalizePath(conf, result) result = "" -template patchModule() {.dirty.} = +template patchModule(conf: ConfigRef) {.dirty.} = if result.len > 0 and gModuleOverrides.len > 0: let key = getPackageName(result) & "_" & splitFile(result).name if gModuleOverrides.hasKey(key): let ov = gModuleOverrides[key] if ov.len > 0: result = ov -proc findFile*(f: string): string {.procvar.} = +proc findFile*(conf: ConfigRef; f: string): string {.procvar.} = if f.isAbsolute: result = if f.existsFile: f else: "" else: - result = f.rawFindFile + result = rawFindFile(conf, f) if result.len == 0: - result = f.toLowerAscii.rawFindFile + result = rawFindFile(conf, f.toLowerAscii) if result.len == 0: - result = f.rawFindFile2 + result = rawFindFile2(conf, f) if result.len == 0: - result = f.toLowerAscii.rawFindFile2 - patchModule() + result = rawFindFile2(conf, f.toLowerAscii) + patchModule(conf) -proc findModule*(modulename, currentModule: string): string = +proc findModule*(conf: ConfigRef; modulename, currentModule: string): string = # returns path to module when defined(nimfix): # '.nimfix' modules are preferred over '.nim' modules so that specialized @@ -389,16 +444,16 @@ proc findModule*(modulename, currentModule: string): string = let currentPath = currentModule.splitFile.dir result = currentPath / m if not existsFile(result): - result = findFile(m) + result = findFile(conf, m) if existsFile(result): return result let m = addFileExt(modulename, NimExt) let currentPath = currentModule.splitFile.dir result = currentPath / m if not existsFile(result): - result = findFile(m) - patchModule() + result = findFile(conf, m) + patchModule(conf) -proc findProjectNimFile*(pkg: string): string = +proc findProjectNimFile*(conf: ConfigRef; pkg: string): string = const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"] var candidates: seq[string] = @[] for k, f in os.walkDir(pkg, relative=true): @@ -423,10 +478,10 @@ proc canonDynlibName(s: string): string = else: result = s.substr(start) -proc inclDynlibOverride*(lib: string) = +proc inclDynlibOverride*(conf: ConfigRef; lib: string) = gDllOverrides[lib.canonDynlibName] = "true" -proc isDynlibOverride*(lib: string): bool = +proc isDynlibOverride*(conf: ConfigRef; lib: string): bool = result = gDynlibOverrideAll or gDllOverrides.hasKey(lib.canonDynlibName) proc binaryStrSearch*(x: openArray[string], y: string): int = diff --git a/compiler/parser.nim b/compiler/parser.nim index 14683e3074..7a23ed6a9b 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -27,7 +27,7 @@ when isMainModule: outp.close import - llstream, lexer, idents, strutils, ast, astalgo, msgs, options + llstream, lexer, idents, strutils, ast, astalgo, msgs, options, configuration type TParser* = object # A TParser object represents a file that @@ -97,7 +97,7 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, proc openParser*(p: var TParser, filename: string, inputStream: PLLStream, cache: IdentCache; config: ConfigRef; strongSpaces=false) = - openParser(p, filename.fileInfoIdx, inputStream, cache, config, strongSpaces) + openParser(p, fileInfoIdx(config, filename), inputStream, cache, config, strongSpaces) proc closeParser(p: var TParser) = ## Close a parser, freeing up its resources. @@ -107,9 +107,13 @@ proc parMessage(p: TParser, msg: TMsgKind, arg = "") = ## Produce and emit the parser message `arg` to output. lexMessageTok(p.lex, msg, p.tok, arg) -proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) = +proc parMessage(p: TParser, msg: string, tok: TToken) = ## Produce and emit a parser message to output about the token `tok` - parMessage(p, msg, prettyTok(tok)) + parMessage(p, errGenerated, msg % prettyTok(tok)) + +proc parMessage(p: TParser, arg: string) = + ## Produce and emit the parser message `arg` to output. + lexMessageTok(p.lex, errGenerated, p.tok, arg) template withInd(p, body: untyped) = let oldInd = p.currInd @@ -142,6 +146,12 @@ proc skipComment(p: var TParser, node: PNode) = proc flexComment(p: var TParser, node: PNode) = if p.tok.indent < 0 or realInd(p): rawSkipComment(p, node) +const + errInvalidIndentation = "invalid indentation" + errIdentifierExpected = "identifier expected, but got '$1'" + errExprExpected = "expression expected, but found '$1'" + errTokenExpected = "'$1' expected" + proc skipInd(p: var TParser) = if p.tok.indent >= 0: if not realInd(p): parMessage(p, errInvalidIndentation) @@ -160,11 +170,11 @@ proc getTokNoInd(p: var TParser) = proc expectIdentOrKeyw(p: TParser) = if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType): - lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) + lexMessage(p.lex, errGenerated, errIdentifierExpected % prettyTok(p.tok)) proc expectIdent(p: TParser) = if p.tok.tokType != tkSymbol: - lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) + lexMessage(p.lex, errGenerated, errIdentifierExpected % prettyTok(p.tok)) proc eat(p: var TParser, tokType: TTokType) = ## Move the parser to the next token if the current token is of type @@ -172,7 +182,8 @@ proc eat(p: var TParser, tokType: TTokType) = if p.tok.tokType == tokType: getTok(p) else: - lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType]) + lexMessage(p.lex, errGenerated, + "expected " & TokTypeToStr[tokType] & ", but got: " & prettyTok(p.tok)) proc parLineInfo(p: TParser): TLineInfo = ## Retrieve the line information associated with the parser's current state. @@ -878,7 +889,7 @@ proc parsePragma(p: var TParser): PNode = skipComment(p, a) optPar(p) if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p) - else: parMessage(p, errTokenExpected, ".}") + else: parMessage(p, "expected '.}'") dec p.inPragma proc identVis(p: var TParser; allowDot=false): PNode = @@ -939,7 +950,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode = else: addSon(result, newNodeP(nkEmpty, p)) if p.tok.tokType != tkEquals and withBothOptional notin flags: - parMessage(p, errColonOrEqualsExpected, p.tok) + parMessage(p, "':' or '=' expected, but got '$1'", p.tok) if p.tok.tokType == tkEquals: getTok(p) optInd(p, result) @@ -1012,7 +1023,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode = parMessage(p, errGenerated, "the syntax is 'parameter: var T', not 'var parameter: T'") break else: - parMessage(p, errTokenExpected, ")") + parMessage(p, "expected closing ')'") break addSon(result, a) if p.tok.tokType notin {tkComma, tkSemiColon}: break @@ -1173,7 +1184,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode = if mode == pmTypeDef: result = parseTypeClass(p) else: - parMessage(p, errInvalidToken, p.tok) + parMessage(p, "the 'concept' keyword is only valid in 'type' sections") of tkStatic: let info = parLineInfo(p) getTokNoInd(p) @@ -1283,7 +1294,7 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode = if nextBlock.kind == nkElse: break else: if openingParams.kind != nkEmpty: - parMessage(p, errTokenExpected, ":") + parMessage(p, "expected ':'") proc parseExprStmt(p: var TParser): PNode = #| exprStmt = simpleExpr @@ -1518,7 +1529,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode = addSon(b, parseStmt(p)) addSon(result, b) if b.kind == nkFinally: break - if b == nil: parMessage(p, errTokenExpected, "except") + if b == nil: parMessage(p, "expected 'except'") proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode = #| exceptBlock = 'except' colcom stmt @@ -1573,7 +1584,7 @@ proc parseAsm(p: var TParser): PNode = of tkTripleStrLit: addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p)) else: - parMessage(p, errStringLiteralExpected) + parMessage(p, "the 'asm' statement takes a string literal") addSon(result, ast.emptyNode) return getTok(p) @@ -1752,7 +1763,7 @@ proc parseEnum(p: var TParser): PNode = p.tok.tokType == tkEof: break if result.len <= 1: - lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok)) + parMessage(p, errIdentifierExpected, p.tok) proc parseObjectPart(p: var TParser): PNode proc parseObjectWhen(p: var TParser): PNode = @@ -2115,7 +2126,7 @@ proc parseStmt(p: var TParser): PNode = case p.tok.tokType of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc, tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar: - parMessage(p, errComplexStmtRequiresInd) + parMessage(p, "complex statement requires indentation") result = ast.emptyNode else: if p.inSemiStmtList > 0: diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 6ef42f15ec..0cd5d1be21 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -131,10 +131,10 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; processSwitch(a.getString 0, a.getString 1, passPP, module.info, config) cbconf hintImpl: processSpecificNote(a.getString 0, wHint, passPP, module.info, - a.getString 1) + a.getString 1, config) cbconf warningImpl: processSpecificNote(a.getString 0, wWarning, passPP, module.info, - a.getString 1) + a.getString 1, config) cbconf patchFile: let key = a.getString(0) & "_" & a.getString(1) var val = a.getString(2).addFileExt(NimExt) From 0d56dd4677b8f6b080844db8655b41c10bee68c1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 May 2018 13:12:42 +0200 Subject: [PATCH 174/214] big refactoring: magicsys compiles again --- compiler/filter_tmpl.nim | 23 ++--- compiler/filters.nim | 43 ++++----- compiler/magicsys.nim | 189 ++++++++++++++++++-------------------- compiler/modulegraphs.nim | 9 ++ compiler/msgs.nim | 4 +- compiler/options.nim | 6 ++ compiler/renderer.nim | 18 ++-- compiler/rodread.nim | 118 +++++++++++++----------- compiler/syntaxes.nim | 34 +++---- compiler/types.nim | 69 +++++++------- 10 files changed, 269 insertions(+), 244 deletions(-) diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 545bea950e..9bdc41016d 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -27,7 +27,7 @@ type emit, conc, toStr: string curly, bracket, par: int pendingExprLine: bool - + config: ConfigRef const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'} @@ -90,7 +90,7 @@ proc parseLine(p: var TTmplParser) = dec(p.indent, 2) else: p.info.col = int16(j) - localError(p.info, errXNotAllowedHere, "end") + localError(p.config, p.info, "'end' does not close a control flow construct") llStreamWrite(p.outp, spaces(p.indent)) llStreamWrite(p.outp, "#end") of "if", "when", "try", "while", "for", "block", "case", "proc", "iterator", @@ -175,7 +175,7 @@ proc parseLine(p: var TTmplParser) = llStreamWrite(p.outp, p.x[j]) inc(j) if curly > 0: - localError(p.info, errXExpected, "}") + localError(p.config, p.info, "expected closing '}'") break llStreamWrite(p.outp, ')') llStreamWrite(p.outp, p.conc) @@ -197,22 +197,23 @@ proc parseLine(p: var TTmplParser) = inc(j) else: p.info.col = int16(j) - localError(p.info, errInvalidExpression, "$") + localError(p.config, p.info, "invalid expression") else: llStreamWrite(p.outp, p.x[j]) inc(j) llStreamWrite(p.outp, "\\n\"") -proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream = +proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode; conf: ConfigRef): PLLStream = var p: TTmplParser - p.info = newLineInfo(filename, 0, 0) + p.config = conf + p.info = newLineInfo(conf, filename, 0, 0) p.outp = llStreamOpen("") p.inp = stdin - p.subsChar = charArg(call, "subschar", 1, '$') - p.nimDirective = charArg(call, "metachar", 2, '#') - p.emit = strArg(call, "emit", 3, "result.add") - p.conc = strArg(call, "conc", 4, " & ") - p.toStr = strArg(call, "tostring", 5, "$") + p.subsChar = charArg(conf, call, "subschar", 1, '$') + p.nimDirective = charArg(conf, call, "metachar", 2, '#') + p.emit = strArg(conf, call, "emit", 3, "result.add") + p.conc = strArg(conf, call, "conc", 4, " & ") + p.toStr = strArg(conf, call, "tostring", 5, "$") p.x = newStringOfCap(120) # do not process the first line which contains the directive: if llStreamReadLine(p.inp, p.x): diff --git a/compiler/filters.nim b/compiler/filters.nim index 37df628ed7..3ebbad678f 100644 --- a/compiler/filters.nim +++ b/compiler/filters.nim @@ -13,43 +13,44 @@ import llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, renderer -proc invalidPragma(n: PNode) = - localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments})) +proc invalidPragma(conf: ConfigRef; n: PNode) = + localError(conf, n.info, + "'$1' not allowed here" % renderTree(n, {renderNoComments})) -proc getArg(n: PNode, name: string, pos: int): PNode = +proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode = result = nil if n.kind in {nkEmpty..nkNilLit}: return for i in countup(1, sonsLen(n) - 1): if n.sons[i].kind == nkExprEqExpr: - if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n) + if n.sons[i].sons[0].kind != nkIdent: invalidPragma(conf, n) if cmpIgnoreStyle(n.sons[i].sons[0].ident.s, name) == 0: return n.sons[i].sons[1] elif i == pos: return n.sons[i] -proc charArg*(n: PNode, name: string, pos: int, default: char): char = - var x = getArg(n, name, pos) +proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char = + var x = getArg(conf, n, name, pos) if x == nil: result = default elif x.kind == nkCharLit: result = chr(int(x.intVal)) - else: invalidPragma(n) + else: invalidPragma(conf, n) -proc strArg*(n: PNode, name: string, pos: int, default: string): string = - var x = getArg(n, name, pos) +proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string = + var x = getArg(conf, n, name, pos) if x == nil: result = default elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal - else: invalidPragma(n) + else: invalidPragma(conf, n) -proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool = - var x = getArg(n, name, pos) +proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool = + var x = getArg(conf, n, name, pos) if x == nil: result = default elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false - else: invalidPragma(n) + else: invalidPragma(conf, n) -proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream = - var pattern = strArg(call, "startswith", 1, "") - var leading = boolArg(call, "leading", 2, true) - var trailing = boolArg(call, "trailing", 3, true) +proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream = + var pattern = strArg(conf, call, "startswith", 1, "") + var leading = boolArg(conf, call, "leading", 2, true) + var trailing = boolArg(conf, call, "trailing", 3, true) result = llStreamOpen("") var line = newStringOfCap(80) while llStreamReadLine(stdin, line): @@ -60,10 +61,10 @@ proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream = llStreamWriteln(result, line) llStreamClose(stdin) -proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream = - var sub = strArg(call, "sub", 1, "") - if len(sub) == 0: invalidPragma(call) - var by = strArg(call, "by", 2, "") +proc filterReplace*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream = + var sub = strArg(conf, call, "sub", 1, "") + if len(sub) == 0: invalidPragma(conf, call) + var by = strArg(conf, call, "by", 2, "") result = llStreamOpen("") var line = newStringOfCap(80) while llStreamReadLine(stdin, line): diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 6a9d690823..75026d5f44 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -10,63 +10,59 @@ # Built-in types and compilerprocs are registered here. import - ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread + ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread, + modulegraphs -var systemModule*: PSym +proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt] -var - gSysTypes: array[TTypeKind, PType] - compilerprocs: TStrTable - exposed: TStrTable +proc registerSysType*(g: ModuleGraph; t: PType) = + if g.sysTypes[t.kind] == nil: g.sysTypes[t.kind] = t -proc nilOrSysInt*: PType = gSysTypes[tyInt] - -proc registerSysType*(t: PType) = - if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t - -proc newSysType(kind: TTypeKind, size: int): PType = - result = newType(kind, systemModule) +proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType = + result = newType(kind, g.systemModule) result.size = size result.align = size.int16 -proc getSysSym*(name: string): PSym = - result = strTableGet(systemModule.tab, getIdent(name)) +proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = + result = strTableGet(g.systemModule.tab, getIdent(name)) if result == nil: - rawMessage(errSystemNeeds, name) - result = newSym(skError, getIdent(name), systemModule, systemModule.info) - result.typ = newType(tyError, systemModule) + localError(g.config, info, "system module needs: " & name) + result = newSym(skError, getIdent(name), g.systemModule, g.systemModule.info) + result.typ = newType(tyError, g.systemModule) if result.kind == skStub: loadStub(result) if result.kind == skAlias: result = result.owner -proc createMagic*(name: string, m: TMagic): PSym = +proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = result = newSym(skProc, getIdent(name), nil, unknownLineInfo()) result.magic = m -let - opNot* = createMagic("not", mNot) - opContains* = createMagic("contains", mInSet) +when false: + let + opNot* = createMagic("not", mNot) + opContains* = createMagic("contains", mInSet) -proc getSysMagic*(name: string, m: TMagic): PSym = +proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym = var ti: TIdentIter let id = getIdent(name) - var r = initIdentIter(ti, systemModule.tab, id) + var r = initIdentIter(ti, g.systemModule.tab, id) while r != nil: if r.kind == skStub: loadStub(r) if r.magic == m: # prefer the tyInt variant: if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r result = r - r = nextIdentIter(ti, systemModule.tab) + r = nextIdentIter(ti, g.systemModule.tab) if result != nil: return result - rawMessage(errSystemNeeds, name) - result = newSym(skError, id, systemModule, systemModule.info) - result.typ = newType(tyError, systemModule) + localError(g.config, info, "system module needs: " & name) + result = newSym(skError, id, g.systemModule, g.systemModule.info) + result.typ = newType(tyError, g.systemModule) -proc sysTypeFromName*(name: string): PType = - result = getSysSym(name).typ +proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType = + result = getSysSym(g, info, name).typ -proc getSysType*(kind: TTypeKind): PType = - result = gSysTypes[kind] +proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType = + template sysTypeFromName(s: string): untyped = sysTypeFromName(g, info, s) + result = g.sysTypes[kind] if result == nil: case kind of tyInt: result = sysTypeFromName("int") @@ -88,51 +84,49 @@ proc getSysType*(kind: TTypeKind): PType = of tyString: result = sysTypeFromName("string") of tyCString: result = sysTypeFromName("cstring") of tyPointer: result = sysTypeFromName("pointer") - of tyNil: result = newSysType(tyNil, ptrSize) - else: internalError("request for typekind: " & $kind) - gSysTypes[kind] = result + of tyNil: result = newSysType(g, tyNil, ptrSize) + else: internalError(g.config, "request for typekind: " & $kind) + g.sysTypes[kind] = result if result.kind != kind: - internalError("wanted: " & $kind & " got: " & $result.kind) - if result == nil: internalError("type not found: " & $kind) + internalError(g.config, "wanted: " & $kind & " got: " & $result.kind) + if result == nil: internalError(g.config, "type not found: " & $kind) -var - intTypeCache: array[-5..64, PType] +proc resetSysTypes*(g: ModuleGraph) = + g.systemModule = nil + initStrTable(g.compilerprocs) + initStrTable(g.exposed) + for i in low(g.sysTypes)..high(g.sysTypes): + g.sysTypes[i] = nil -proc resetSysTypes* = - systemModule = nil - initStrTable(compilerprocs) - initStrTable(exposed) - for i in low(gSysTypes)..high(gSysTypes): - gSysTypes[i] = nil + for i in low(g.intTypeCache)..high(g.intTypeCache): + g.intTypeCache[i] = nil - for i in low(intTypeCache)..high(intTypeCache): - intTypeCache[i] = nil - -proc getIntLitType*(literal: PNode): PType = +proc getIntLitType*(g: ModuleGraph; literal: PNode): PType = # we cache some common integer literal types for performance: let value = literal.intVal - if value >= low(intTypeCache) and value <= high(intTypeCache): - result = intTypeCache[value.int] + if value >= low(g.intTypeCache) and value <= high(g.intTypeCache): + result = g.intTypeCache[value.int] if result == nil: - let ti = getSysType(tyInt) + let ti = getSysType(g, literal.info, tyInt) result = copyType(ti, ti.owner, false) result.n = literal - intTypeCache[value.int] = result + g.intTypeCache[value.int] = result else: - let ti = getSysType(tyInt) + let ti = getSysType(g, literal.info, tyInt) result = copyType(ti, ti.owner, false) result.n = literal -proc getFloatLitType*(literal: PNode): PType = +proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType = # for now we do not cache these: - result = newSysType(tyFloat, size=8) + result = newSysType(g, tyFloat, size=8) result.n = literal proc skipIntLit*(t: PType): PType {.inline.} = - if t.n != nil: - if t.kind in {tyInt, tyFloat}: - return getSysType(t.kind) - result = t + if t.n != nil and t.kind in {tyInt, tyFloat}: + result = copyType(t, t.owner, false) + result.n = nil + else: + result = t proc addSonSkipIntLit*(father, son: PType) = if isNil(father.sons): father.sons = @[] @@ -140,60 +134,59 @@ proc addSonSkipIntLit*(father, son: PType) = add(father.sons, s) propagateToOwner(father, s) -proc setIntLitType*(result: PNode) = +proc setIntLitType*(g: ModuleGraph; result: PNode) = let i = result.intVal case platform.intSize - of 8: result.typ = getIntLitType(result) + of 8: result.typ = getIntLitType(g, result) of 4: if i >= low(int32) and i <= high(int32): - result.typ = getIntLitType(result) + result.typ = getIntLitType(g, result) else: - result.typ = getSysType(tyInt64) + result.typ = getSysType(g, result.info, tyInt64) of 2: if i >= low(int16) and i <= high(int16): - result.typ = getIntLitType(result) + result.typ = getIntLitType(g, result) elif i >= low(int32) and i <= high(int32): - result.typ = getSysType(tyInt32) + result.typ = getSysType(g, result.info, tyInt32) else: - result.typ = getSysType(tyInt64) + result.typ = getSysType(g, result.info, tyInt64) of 1: # 8 bit CPUs are insane ... if i >= low(int8) and i <= high(int8): - result.typ = getIntLitType(result) + result.typ = getIntLitType(g, result) elif i >= low(int16) and i <= high(int16): - result.typ = getSysType(tyInt16) + result.typ = getSysType(g, result.info, tyInt16) elif i >= low(int32) and i <= high(int32): - result.typ = getSysType(tyInt32) + result.typ = getSysType(g, result.info, tyInt32) else: - result.typ = getSysType(tyInt64) - else: internalError(result.info, "invalid int size") - -proc getCompilerProc*(name: string): PSym = - let ident = getIdent(name) - result = strTableGet(compilerprocs, ident) - if result == nil: - result = strTableGet(rodCompilerprocs, ident) - if result != nil: - strTableAdd(compilerprocs, result) - if result.kind == skStub: loadStub(result) - if result.kind == skAlias: result = result.owner - -proc registerCompilerProc*(s: PSym) = - strTableAdd(compilerprocs, s) - -proc registerNimScriptSymbol*(s: PSym) = - # Nimscript symbols must be al unique: - let conflict = strTableGet(exposed, s.name) - if conflict == nil: - strTableAdd(exposed, s) + result.typ = getSysType(g, result.info, tyInt64) else: - localError(s.info, "symbol conflicts with other .exportNims symbol at: " & - $conflict.info) + internalError(g.config, result.info, "invalid int size") -proc getNimScriptSymbol*(name: string): PSym = - strTableGet(exposed, getIdent(name)) +proc getCompilerProc*(g: ModuleGraph; name: string): PSym = + let ident = getIdent(name) + result = strTableGet(g.compilerprocs, ident) + when false: + if result == nil: + result = strTableGet(g.rodCompilerprocs, ident) + if result != nil: + strTableAdd(g.compilerprocs, result) + if result.kind == skStub: loadStub(result) + if result.kind == skAlias: result = result.owner -proc resetNimScriptSymbols*() = initStrTable(exposed) +proc registerCompilerProc*(g: ModuleGraph; s: PSym) = + strTableAdd(g.compilerprocs, s) -initStrTable(compilerprocs) -initStrTable(exposed) +proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) = + # Nimscript symbols must be al unique: + let conflict = strTableGet(g.exposed, s.name) + if conflict == nil: + strTableAdd(g.exposed, s) + else: + localError(g.config, s.info, + "symbol conflicts with other .exportNims symbol at: " & $conflict.info) + +proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym = + strTableGet(g.exposed, getIdent(name)) + +proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 6c14a46e82..5f741a3b34 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -44,6 +44,11 @@ type usageSym*: PSym # for nimsuggest owners*: seq[PSym] methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]] + systemModule*: PSym + sysTypes*: array[TTypeKind, PType] + compilerprocs*: TStrTable + exposed*: TStrTable + intTypeCache*: array[-5..64, PType] proc hash*(x: FileIndex): Hash {.borrow.} @@ -65,6 +70,8 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = result.config = config result.owners = @[] result.methods = @[] + initStrTable(result.compilerprocs) + initStrTable(result.exposed) proc resetAllModules*(g: ModuleGraph) = initStrTable(packageSyms) @@ -75,6 +82,8 @@ proc resetAllModules*(g: ModuleGraph) = usageSym = nil owners = @[] methods = @[] + initStrTable(compilerprocs) + initStrTable(exposed) proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 08be515d13..5b75596b88 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -629,9 +629,9 @@ proc quotedFilename*(i: TLineInfo): Rope = ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) = case err of rInvalidFormatStr: - internalError(newConfigRef(), "ropes: invalid format string: " & msg) + internalError(newPartialConfigRef(), "ropes: invalid format string: " & msg) of rCannotOpenFile: - rawMessage(newConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg) + rawMessage(newPartialConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg) proc listWarnings*(conf: ConfigRef) = msgWriteln("Warnings:") diff --git a/compiler/options.nim b/compiler/options.nim index ec87ed805e..4c5b6b6689 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -141,6 +141,12 @@ proc newConfigRef*(): ConfigRef = notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], symbols: newStringTable(modeStyleInsensitive)) +proc newPartialConfigRef*(): ConfigRef = + ## create a new ConfigRef that is only good enough for error reporting. + result = ConfigRef(foreignPackageNotes: {hintProcessing, warnUnknownMagic, + hintQuitCalled, hintExecuting}, + notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1]) + proc cppDefine*(c: ConfigRef; define: string) = c.cppDefines.incl define diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 996168412b..a47c77464f 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -10,7 +10,7 @@ # This module implements the renderer of the standard Nim representation. import - lexer, options, idents, strutils, ast, msgs + lexer, options, idents, strutils, ast, msgs, configuration type TRenderFlag* = enum @@ -40,6 +40,7 @@ type when defined(nimpretty): pendingNewlineCount: int fid*: FileIndex + config*: ConfigRef # We render the source code in a two phases: The first # determines how long the subtree will likely be, the second @@ -90,7 +91,7 @@ const MaxLineLen = 80 LineCommentColumn = 30 -proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = +proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) = g.comStack = @[] g.tokens = @[] g.indent = 0 @@ -102,6 +103,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = g.pendingNL = -1 g.pendingWhitespace = -1 g.inGenericParams = false + g.config = config proc addTok(g: var TSrcGen, kind: TTokType, s: string) = var length = len(g.tokens) @@ -377,7 +379,7 @@ proc atom(g: TSrcGen; n: PNode): string = if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s else: result = "[type node]" else: - internalError("rnimsyn.atom " & $n.kind) + internalError(g.config, "rnimsyn.atom " & $n.kind) result = "" proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int = @@ -1422,11 +1424,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gTypeClassTy(g, n) else: #nkNone, nkExplicitTypeListCall: - internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')') + internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')') proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string = var g: TSrcGen - initSrcGen(g, renderFlags) + initSrcGen(g, renderFlags, newPartialConfigRef()) # do not indent the initial statement list so that # writeFile("file.nim", repr n) # produces working Nim code: @@ -1444,7 +1446,7 @@ proc renderModule*(n: PNode, infile, outfile: string, var f: File g: TSrcGen - initSrcGen(g, renderFlags) + initSrcGen(g, renderFlags, newPartialConfigRef()) g.fid = fid for i in countup(0, sonsLen(n) - 1): gsub(g, n.sons[i]) @@ -1460,10 +1462,10 @@ proc renderModule*(n: PNode, infile, outfile: string, write(f, g.buf) close(f) else: - rawMessage(errCannotOpenFile, outfile) + rawMessage(g.config, errGenerated, "cannot open file: " & outfile) proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = - initSrcGen(r, renderFlags) + initSrcGen(r, renderFlags, newPartialConfigRef()) gsub(r, n) proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) = diff --git a/compiler/rodread.nim b/compiler/rodread.nim index f55c3279cb..9fab37632f 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -90,7 +90,8 @@ import os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, - ropes, idents, std / sha1, idgen, types, rodutils, memfiles, tables + ropes, idents, std / sha1, idgen, types, rodutils, memfiles, tables, + configuration type TReasonForRecompile* = enum ## all the reasons that can trigger recompilation @@ -143,6 +144,7 @@ type origFile: string inViewMode: bool cache*: IdentCache + config: ConfigRef PRodReader* = ref TRodReader @@ -222,14 +224,14 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo, var fl = decodeStr(r.s, r.pos) result.ident = r.cache.getIdent(fl) else: - internalError(result.info, "decodeNode: nkIdent") + internalError(r.config, result.info, "decodeNode: nkIdent") of nkSym: if r.s[r.pos] == '!': inc(r.pos) var id = decodeVInt(r.s, r.pos) result.sym = rrGetSym(r, id, result.info) else: - internalError(result.info, "decodeNode: nkSym") + internalError(r.config, result.info, "decodeNode: nkSym") else: var i = 0 while r.s[r.pos] != ')': @@ -241,9 +243,9 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo, addSonNilAllowed(result, decodeNodeLazyBody(r, result.info, nil)) inc i if r.s[r.pos] == ')': inc(r.pos) - else: internalError(result.info, "decodeNode: ')' missing") + else: internalError(r.config, result.info, "decodeNode: ')' missing") else: - internalError(fInfo, "decodeNode: '(' missing " & $r.pos) + internalError(r.config, fInfo, "decodeNode: '(' missing " & $r.pos) proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = result = decodeNodeLazyBody(r, fInfo, nil) @@ -277,7 +279,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) = else: loc.r = nil if r.s[r.pos] == '>': inc(r.pos) - else: internalError(info, "decodeLoc " & r.s[r.pos]) + else: internalError(r.config, info, "decodeLoc " & r.s[r.pos]) proc decodeType(r: PRodReader, info: TLineInfo): PType = result = nil @@ -294,7 +296,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType = setId(result.id) if debugIds: registerID(result) else: - internalError(info, "decodeType: no id") + internalError(r.config, info, "decodeType: no id") # here this also avoids endless recursion for recursive type idTablePut(gTypeTable, result, result) if r.s[r.pos] == '(': result.n = decodeNode(r, unknownLineInfo()) @@ -345,14 +347,14 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType = doAssert r.s[r.pos] == '\20' inc(r.pos) let y = rrGetSym(r, decodeVInt(r.s, r.pos), info) - result.methods.safeAdd((x, y)) + result.methods.add((x, y)) decodeLoc(r, result.loc, info) while r.s[r.pos] == '^': inc(r.pos) if r.s[r.pos] == '(': inc(r.pos) if r.s[r.pos] == ')': inc(r.pos) - else: internalError(info, "decodeType ^(" & r.s[r.pos]) + else: internalError(r.config, info, "decodeType ^(" & r.s[r.pos]) rawAddSon(result, nil) else: var d = decodeVInt(r.s, r.pos) @@ -364,10 +366,10 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib = new(result) inc(r.pos) result.kind = TLibKind(decodeVInt(r.s, r.pos)) - if r.s[r.pos] != '|': internalError("decodeLib: 1") + if r.s[r.pos] != '|': internalError(r.config, "decodeLib: 1") inc(r.pos) result.name = rope(decodeStr(r.s, r.pos)) - if r.s[r.pos] != '|': internalError("decodeLib: 2") + if r.s[r.pos] != '|': internalError(r.config, "decodeLib: 2") inc(r.pos) result.path = decodeNode(r, info) @@ -385,7 +387,7 @@ proc decodeInstantiations(r: PRodReader; info: TLineInfo; if r.s[r.pos] == '\20': inc(r.pos) ii.compilesId = decodeVInt(r.s, r.pos) - s.safeAdd ii + s.add ii proc decodeSym(r: PRodReader, info: TLineInfo): PSym = var @@ -403,12 +405,12 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym = id = decodeVInt(r.s, r.pos) setId(id) else: - internalError(info, "decodeSym: no id") + internalError(r.config, info, "decodeSym: no id") if r.s[r.pos] == '&': inc(r.pos) ident = r.cache.getIdent(decodeStr(r.s, r.pos)) else: - internalError(info, "decodeSym: no ident") + internalError(r.config, info, "decodeSym: no ident") #echo "decoding: {", ident.s result = r.syms.getOrDefault(id) if result == nil: @@ -417,7 +419,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym = r.syms[result.id] = result if debugIds: registerID(result) elif result.id != id: - internalError(info, "decodeSym: wrong id") + internalError(r.config, info, "decodeSym: wrong id") elif result.kind != skStub and not r.inViewMode: # we already loaded the symbol return @@ -465,7 +467,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym = of skType, skGenericParam: while r.s[r.pos] == '\14': inc(r.pos) - result.typeInstCache.safeAdd rrGetType(r, decodeVInt(r.s, r.pos), result.info) + result.typeInstCache.add rrGetType(r, decodeVInt(r.s, r.pos), result.info) of routineKinds: decodeInstantiations(r, result.info, result.procInstCache) if r.s[r.pos] == '\16': @@ -512,7 +514,7 @@ proc skipSection(r: PRodReader) = else: discard inc(r.pos) else: - internalError("skipSection " & $r.line) + internalError(r.config, "skipSection " & $r.line) proc rdWord(r: PRodReader): string = result = "" @@ -530,7 +532,7 @@ proc newStub(r: PRodReader, name: string, id: int): PSym = if debugIds: registerID(result) proc processInterf(r: PRodReader, module: PSym) = - if r.interfIdx == 0: internalError("processInterf") + if r.interfIdx == 0: internalError(r.config, "processInterf") r.pos = r.interfIdx while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): var w = decodeStr(r.s, r.pos) @@ -543,7 +545,7 @@ proc processInterf(r: PRodReader, module: PSym) = r.syms[s.id] = s proc processCompilerProcs(r: PRodReader, module: PSym) = - if r.compilerProcsIdx == 0: internalError("processCompilerProcs") + if r.compilerProcsIdx == 0: internalError(r.config, "processCompilerProcs") r.pos = r.compilerProcsIdx while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): var w = decodeStr(r.s, r.pos) @@ -637,10 +639,10 @@ proc processRodFile(r: PRodReader, hash: SecureHash) = while r.s[r.pos] > '\x0A': w = decodeStr(r.s, r.pos) inc(d) - if not condsyms.isDefined(r.cache.getIdent(w)): + if not isDefined(r.config, w): r.reason = rrDefines #MessageOut('not defined, but should: ' + w); if r.s[r.pos] == ' ': inc(r.pos) - if d != countDefinedSymbols(): r.reason = rrDefines + if d != countDefinedSymbols(r.config.symbols): r.reason = rrDefines of "FILES": inc(r.pos, 2) # skip "(\10" inc(r.line) @@ -648,7 +650,7 @@ proc processRodFile(r: PRodReader, hash: SecureHash) = let finalPath = decodeStr(r.s, r.pos) #let resolvedPath = relativePath.findModule(r.origFile) #let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath - r.files.add(finalPath.fileInfoIdx) + r.files.add(fileInfoIdx(r.config, finalPath)) inc(r.pos) # skip #10 inc(r.line) if r.s[r.pos] == ')': inc(r.pos) @@ -696,7 +698,7 @@ proc processRodFile(r: PRodReader, hash: SecureHash) = r.initIdx = r.pos + 2 # "(\10" skipSection(r) else: - internalError("invalid section: '" & section & + internalError(r.config, "invalid section: '" & section & "' at " & $r.line & " in " & r.filename) #MsgWriteln("skipping section: " & section & # " at " & $r.line & " in " & r.filename) @@ -712,9 +714,11 @@ proc startsWith(buf: cstring, token: string, pos = 0): bool = result = s == token.len proc newRodReader(modfilename: string, hash: SecureHash, - readerIndex: int; cache: IdentCache): PRodReader = + readerIndex: int; cache: IdentCache; + config: ConfigRef): PRodReader = new(result) result.cache = cache + result.config = config try: result.memfile = memfiles.open(modfilename) except OSError: @@ -757,13 +761,13 @@ proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType = # load the type: var oldPos = r.pos var d = iiTableGet(r.index.tab, id) - if d == InvalidKey: internalError(info, "rrGetType") + if d == InvalidKey: internalError(r.config, info, "rrGetType") r.pos = d + r.dataIdx result = decodeType(r, info) r.pos = oldPos type - TFileModuleRec{.final.} = object + TFileModuleRec = object filename*: string reason*: TReasonForRecompile rd*: PRodReader @@ -776,7 +780,7 @@ var gMods*: TFileModuleMap = @[] proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym = # all compiled modules - if rd.dataIdx == 0: internalError(info, "dataIdx == 0") + if rd.dataIdx == 0: internalError(rd.config, info, "dataIdx == 0") var oldPos = rd.pos rd.pos = offset + rd.dataIdx result = decodeSym(rd, info) @@ -811,7 +815,7 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym = if moduleID < 0: var x = "" encodeVInt(id, x) - internalError(info, "missing from both indexes: +" & x) + internalError(r.config, info, "missing from both indexes: +" & x) var rd = getReader(moduleID) doAssert rd != nil d = iiTableGet(rd.index.tab, id) @@ -821,14 +825,14 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym = var x = "" encodeVInt(id, x) when false: findSomeWhere(id) - internalError(info, "rrGetSym: no reader found: +" & x) + internalError(r.config, info, "rrGetSym: no reader found: +" & x) else: # own symbol: result = decodeSymSafePos(r, d, info) if result != nil and result.kind == skStub: rawLoadStub(result) proc loadInitSection*(r: PRodReader): PNode = - if r.initIdx == 0 or r.dataIdx == 0: internalError("loadInitSection") + if r.initIdx == 0 or r.dataIdx == 0: internalError(r.config, "loadInitSection") var oldPos = r.pos r.pos = r.initIdx result = newNode(nkStmtList) @@ -845,7 +849,7 @@ proc loadConverters(r: PRodReader) = # We have to ensure that no exported converter is a stub anymore, and the # import mechanism takes care of the rest. if r.convertersIdx == 0 or r.dataIdx == 0: - internalError("importConverters") + internalError(r.config, "importConverters") r.pos = r.convertersIdx while r.s[r.pos] > '\x0A': var d = decodeVInt(r.s, r.pos) @@ -854,7 +858,7 @@ proc loadConverters(r: PRodReader) = proc loadMethods(r: PRodReader) = if r.methodsIdx == 0 or r.dataIdx == 0: - internalError("loadMethods") + internalError(r.config, "loadMethods") r.pos = r.methodsIdx while r.s[r.pos] > '\x0A': var d = decodeVInt(r.s, r.pos) @@ -872,7 +876,7 @@ proc getHash*(fileIdx: FileIndex): SecureHash = template growCache*(cache, pos) = if cache.len <= pos: cache.setLen(pos+1) -proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile = +proc checkDep(fileIdx: FileIndex; cache: IdentCache; conf: ConfigRef): TReasonForRecompile = assert fileIdx != InvalidFileIDX growCache gMods, fileIdx.int32 if gMods[fileIdx.int32].reason != rrEmpty: @@ -882,8 +886,8 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile = var hash = getHash(fileIdx) gMods[fileIdx.int32].reason = rrNone # we need to set it here to avoid cycles result = rrNone - var rodfile = toGeneratedFile(filename.withPackageName, RodExt) - var r = newRodReader(rodfile, hash, fileIdx.int32, cache) + var rodfile = toGeneratedFile(conf, filename.withPackageName, RodExt) + var r = newRodReader(rodfile, hash, fileIdx.int32, cache, conf) if r == nil: result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist) else: @@ -894,15 +898,15 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile = # NOTE: we need to process the entire module graph so that no ID will # be used twice! However, compilation speed does not suffer much from # this, since results are cached. - var res = checkDep(systemFileIdx, cache) + var res = checkDep(systemFileIdx, cache, conf) if res != rrNone: result = rrModDeps for i in countup(0, high(r.modDeps)): - res = checkDep(r.modDeps[i], cache) + res = checkDep(r.modDeps[i], cache, conf) if res != rrNone: result = rrModDeps # we cannot break here, because of side-effects of `checkDep` if result != rrNone: - rawMessage(hintProcessing, reasonToFrmt[result] % filename) + rawMessage(conf, hintProcessing, reasonToFrmt[result] % filename) if result != rrNone or optForceFullMake in gGlobalOptions: # recompilation is necessary: if r != nil: memfiles.close(r.memfile) @@ -910,14 +914,14 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile = gMods[fileIdx.int32].rd = r gMods[fileIdx.int32].reason = result # now we know better -proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader = +proc handleSymbolFile*(module: PSym; cache: IdentCache; conf: ConfigRef): PRodReader = if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}: module.id = getID() return nil - idgen.loadMaxIds(options.gProjectPath / options.gProjectName) + idgen.loadMaxIds(conf, options.gProjectPath / options.gProjectName) let fileIdx = module.fileIdx - discard checkDep(fileIdx, cache) - if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile") + discard checkDep(fileIdx, cache, conf) + #if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile") result = gMods[fileIdx.int32].rd if result != nil: module.id = result.moduleID @@ -930,19 +934,20 @@ proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader = module.id = getID() proc rawLoadStub(s: PSym) = - if s.kind != skStub: internalError("loadStub") + assert s.kind == skStub + #if s.kind != skStub: internalError("loadStub") var rd = gMods[s.position].rd var theId = s.id # used for later check var d = iiTableGet(rd.index.tab, s.id) - if d == InvalidKey: internalError("loadStub: invalid key") + #if d == InvalidKey: internalError("loadStub: invalid key") var rs = decodeSymSafePos(rd, d, unknownLineInfo()) - if rs != s: - #echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2), - # "\ns: ", toHex(cast[int](s.position), int.sizeof * 2) - internalError(rs.info, "loadStub: wrong symbol") - elif rs.id != theId: - internalError(rs.info, "loadStub: wrong ID") - #MessageOut('loaded stub: ' + s.name.s); + when false: + if rs != s: + #echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2), + # "\ns: ", toHex(cast[int](s.position), int.sizeof * 2) + internalError(rs.info, "loadStub: wrong symbol") + elif rs.id != theId: + internalError(rs.info, "loadStub: wrong ID") proc loadStub*(s: PSym) = ## loads the stub symbol `s`. @@ -1083,9 +1088,10 @@ proc writeType(f: File; t: PType) = f.write("]\n") proc viewFile(rodfile: string) = - var r = newRodReader(rodfile, secureHash(""), 0, newIdentCache()) + let conf = newConfigRef() + var r = newRodReader(rodfile, secureHash(""), 0, newIdentCache(), conf) if r == nil: - rawMessage(errGenerated, "cannot open file (or maybe wrong version):" & + rawMessage(conf, errGenerated, "cannot open file (or maybe wrong version):" & rodfile) return r.inViewMode = true @@ -1133,9 +1139,9 @@ proc viewFile(rodfile: string) = outf.write("FILES(\n") while r.s[r.pos] != ')': let relativePath = decodeStr(r.s, r.pos) - let resolvedPath = relativePath.findModule(r.origFile) + let resolvedPath = findModule(conf, relativePath, r.origFile) let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath - r.files.add(finalPath.fileInfoIdx) + r.files.add(fileInfoIdx(conf, finalPath)) inc(r.pos) # skip #10 inc(r.line) outf.writeLine finalPath @@ -1227,7 +1233,7 @@ proc viewFile(rodfile: string) = if r.s[r.pos] == ')': inc r.pos outf.write(")\n") else: - internalError("invalid section: '" & section & + internalError(r.config, "invalid section: '" & section & "' at " & $r.line & " in " & r.filename) skipSection(r) if r.s[r.pos] == '\x0A': diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 974df50fb2..4a6474912e 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -11,7 +11,7 @@ import strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser, - filters, filter_tmpl, renderer + filters, filter_tmpl, renderer, configuration type TFilterKind* = enum @@ -30,12 +30,14 @@ type skin*: TParserKind parser*: TParser +template config(p: TParsers): ConfigRef = p.parser.lex.config + proc parseAll*(p: var TParsers): PNode = case p.skin of skinStandard, skinStrongSpaces: result = parser.parseAll(p.parser) of skinEndX: - internalError("parser to implement") + internalError(p.config, "parser to implement") result = ast.emptyNode proc parseTopLevelStmt*(p: var TParsers): PNode = @@ -43,7 +45,7 @@ proc parseTopLevelStmt*(p: var TParsers): PNode = of skinStandard, skinStrongSpaces: result = parser.parseTopLevelStmt(p.parser) of skinEndX: - internalError("parser to implement") + internalError(p.config, "parser to implement") result = ast.emptyNode proc utf8Bom(s: string): int = @@ -86,39 +88,39 @@ proc getFilter(ident: PIdent): TFilterKind = return i result = filtNone -proc getParser(ident: PIdent): TParserKind = +proc getParser(conf: ConfigRef; n: PNode; ident: PIdent): TParserKind = for i in countup(low(TParserKind), high(TParserKind)): if cmpIgnoreStyle(ident.s, parserNames[i]) == 0: return i - rawMessage(errInvalidDirectiveX, ident.s) + localError(conf, n.info, "unknown parser: " & ident.s) -proc getCallee(n: PNode): PIdent = +proc getCallee(conf: ConfigRef; n: PNode): PIdent = if n.kind in nkCallKinds and n.sons[0].kind == nkIdent: result = n.sons[0].ident elif n.kind == nkIdent: result = n.ident else: - rawMessage(errXNotAllowedHere, renderTree(n)) + localError(conf, n.info, "invalid filter: " & renderTree(n)) proc applyFilter(p: var TParsers, n: PNode, filename: string, stdin: PLLStream): PLLStream = - var ident = getCallee(n) + var ident = getCallee(p.config, n) var f = getFilter(ident) case f of filtNone: - p.skin = getParser(ident) + p.skin = getParser(p.config, n, ident) result = stdin of filtTemplate: - result = filterTmpl(stdin, filename, n) + result = filterTmpl(stdin, filename, n, p.config) of filtStrip: - result = filterStrip(stdin, filename, n) + result = filterStrip(p.config, stdin, filename, n) of filtReplace: - result = filterReplace(stdin, filename, n) + result = filterReplace(p.config, stdin, filename, n) if f != filtNone: - if hintCodeBegin in gNotes: - rawMessage(hintCodeBegin, []) + if hintCodeBegin in p.config.notes: + rawMessage(p.config, hintCodeBegin, []) msgWriteln(result.s) - rawMessage(hintCodeEnd, []) + rawMessage(p.config, hintCodeEnd, []) proc evalPipe(p: var TParsers, n: PNode, filename: string, start: PLLStream): PLLStream = @@ -158,7 +160,7 @@ proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode f: File let filename = fileIdx.toFullPathConsiderDirty if not open(f, filename): - rawMessage(errCannotOpenFile, filename) + rawMessage(config, errGenerated, "cannot open file: " & filename) return openParsers(p, fileIdx, llStreamOpen(f), cache, config) result = parseAll(p) diff --git a/compiler/types.nim b/compiler/types.nim index edf4e5b46b..a5c053488b 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -10,7 +10,7 @@ # this module contains routines for accessing and iterating over types import - intsets, ast, astalgo, trees, msgs, strutils, platform, renderer + intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options type TPreferedDesc* = enum @@ -92,8 +92,9 @@ proc getOrdValue*(n: PNode): BiggestInt = of nkNilLit: result = 0 of nkHiddenStdConv: result = getOrdValue(n.sons[1]) else: - localError(n.info, errOrdinalTypeExpected) - result = 0 + #localError(n.info, errOrdinalTypeExpected) + # XXX check usages of getOrdValue + result = high(BiggestInt) proc isIntLit*(t: PType): bool {.inline.} = result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit @@ -105,14 +106,14 @@ 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): - var p = n.sons[i] + let p = n.sons[i] if p.kind == nkSym: add(result, p.sym.name.s) add(result, ": ") add(result, typeToString(p.sym.typ, prefer)) if i != sonsLen(n)-1: add(result, ", ") else: - internalError("getProcHeader") + result.add renderTree(p) add(result, ')') if n.sons[0].typ != nil: result.add(": " & typeToString(n.sons[0].typ, prefer)) @@ -195,10 +196,10 @@ proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, of nkOfBranch, nkElse: result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker) if result: return - else: internalError("searchTypeNodeForAux(record case branch)") + else: discard of nkSym: result = searchTypeForAux(n.sym.typ, p, marker) - else: internalError(n.info, "searchTypeNodeForAux()") + else: discard proc searchTypeForAux(t: PType, predicate: TTypePredicate, marker: var IntSet): bool = @@ -244,7 +245,7 @@ proc analyseObjectWithTypeFieldAux(t: PType, if t == nil: return case t.kind of tyObject: - if (t.n != nil): + if t.n != nil: if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): return frEmbedded for i in countup(0, sonsLen(t) - 1): @@ -453,16 +454,17 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if t.sons[0].kind == tyNone: result = "typedesc" else: result = "type " & typeToString(t.sons[0]) of tyStatic: - internalAssert t.len > 0 if prefer == preferGenericArg and t.n != nil: result = t.n.renderTree else: - result = "static[" & typeToString(t.sons[0]) & "]" + result = "static[" & (if t.len > 0: typeToString(t.sons[0]) else: "") & "]" if t.n != nil: result.add "(" & renderTree(t.n) & ")" of tyUserTypeClass: - internalAssert t.sym != nil and t.sym.owner != nil - if t.isResolvedUserTypeClass: return typeToString(t.lastSon) - return t.sym.owner.name.s + if t.sym != nil and t.sym.owner != nil: + if t.isResolvedUserTypeClass: return typeToString(t.lastSon) + return t.sym.owner.name.s + else: + result = "" of tyBuiltInTypeClass: result = case t.base.kind: of tyVar: "var" @@ -496,7 +498,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyNot: result = "not " & typeToString(t.sons[0]) of tyExpr: - internalAssert t.len == 0 + #internalAssert t.len == 0 result = "untyped" of tyFromExpr: result = renderTree(t.n) @@ -616,9 +618,9 @@ proc firstOrd*(t: PType): BiggestInt = result = firstOrd(lastSon(t)) of tyOrdinal: if t.len > 0: result = firstOrd(lastSon(t)) - else: internalError("invalid kind for firstOrd(" & $t.kind & ')') + else: internalError(newPartialConfigRef(), "invalid kind for firstOrd(" & $t.kind & ')') else: - internalError("invalid kind for firstOrd(" & $t.kind & ')') + internalError(newPartialConfigRef(), "invalid kind for firstOrd(" & $t.kind & ')') result = 0 proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt = @@ -656,9 +658,9 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt = of tyProxy: result = 0 of tyOrdinal: if t.len > 0: result = lastOrd(lastSon(t)) - else: internalError("invalid kind for lastOrd(" & $t.kind & ')') + else: internalError(newPartialConfigRef(), "invalid kind for lastOrd(" & $t.kind & ')') else: - internalError("invalid kind for lastOrd(" & $t.kind & ')') + internalError(newPartialConfigRef(), "invalid kind for lastOrd(" & $t.kind & ')') result = 0 proc lengthOrd*(t: PType): BiggestInt = @@ -748,7 +750,7 @@ proc equalParam(a, b: PSym): TParamsEquality = proc sameConstraints(a, b: PNode): bool = if isNil(a) and isNil(b): return true - internalAssert a.len == b.len + if a.len != b.len: return false for i in 1 ..< a.len: if not exprStructuralEquivalent(a[i].sym.constraint, b[i].sym.constraint): @@ -807,7 +809,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = var y = b.n.sons[i].sym result = x.name.id == y.name.id if not result: break - else: internalError(a.n.info, "sameTuple") + else: + return false elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags: result = false @@ -997,7 +1000,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = cycleCheck() result = sameTypeAux(a.lastSon, b.lastSon, c) of tyNone: result = false - of tyUnused, tyOptAsRef: internalError("sameFlags") + of tyUnused, tyOptAsRef: result = false proc sameBackendType*(x, y: PType): bool = var c = initSameTypeClosure() @@ -1191,7 +1194,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, # for now same as error node; we say it's a valid type as it should # prevent cascading errors: result = nil - of tyUnused, tyOptAsRef: internalError("typeAllowedAux") + of tyUnused, tyOptAsRef: result = t proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType = # returns 'nil' on success and otherwise the part of the type that is @@ -1280,7 +1283,8 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = if res < 0: return res maxSize = max(maxSize, res) maxAlign = max(maxAlign, b) - else: internalError("computeRecSizeAux(record case branch)") + else: + return szIllegalRecursion currOffset = align(currOffset, maxAlign) + maxSize result = align(result, maxAlign) + maxSize a = maxAlign @@ -1441,7 +1445,8 @@ proc getReturnType*(s: PSym): PType = proc getSize*(typ: PType): BiggestInt = result = computeSize(typ) - if result < 0: internalError("getSize: " & $typ.kind) + #if result < 0: internalError("getSize: " & $typ.kind) + # XXX review all usages of 'getSize' proc containsGenericTypeIter(t: PType, closure: RootRef): bool = case t.kind @@ -1469,8 +1474,7 @@ proc baseOfDistinct*(t: PType): PType = while it.kind in {tyPtr, tyRef}: parent = it it = it.lastSon - if it.kind == tyDistinct: - internalAssert parent != nil + if it.kind == tyDistinct and parent != nil: parent.sons[0] = it.sons[0] proc safeInheritanceDiff*(a, b: PType): int = @@ -1502,8 +1506,9 @@ type proc compatibleEffects*(formal, actual: PType): EffectsCompat = # for proc type compatibility checking: assert formal.kind == tyProc and actual.kind == tyProc - internalAssert formal.n.sons[0].kind == nkEffectList - internalAssert actual.n.sons[0].kind == nkEffectList + if formal.n.sons[0].kind != nkEffectList or + actual.n.sons[0].kind != nkEffectList: + return efTagsUnknown var spec = formal.n.sons[0] if spec.len != 0: @@ -1628,14 +1633,14 @@ proc skipHiddenSubConv*(n: PNode): PNode = else: result = n -proc typeMismatch*(info: TLineInfo, formal, actual: PType) = +proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType) = if formal.kind != tyError and actual.kind != tyError: let named = typeToString(formal) let desc = typeToString(formal, preferDesc) let x = if named == desc: named else: named & " = " & desc - var msg = msgKindToString(errTypeMismatch) & + var msg = "type mismatch: got <" & typeToString(actual) & "> " & - msgKindToString(errButExpectedX) % [x] + "but expected " & x & "'" if formal.kind == tyProc and actual.kind == tyProc: case compatibleEffects(formal, actual) @@ -1650,4 +1655,4 @@ proc typeMismatch*(info: TLineInfo, formal, actual: PType) = msg.add "\n.tag effect is 'any tag allowed'" of efLockLevelsDiffer: msg.add "\nlock levels differ" - localError(info, errGenerated, msg) + localError(conf, info, msg) From 5bf31fcabe80f9611a3860a1cbab49407269fe66 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 May 2018 13:39:23 +0200 Subject: [PATCH 175/214] big refactoring: mores stuff compiles --- compiler/modulepaths.nim | 26 +++++++++---------- compiler/nimsets.nim | 55 ++++++++++++++-------------------------- compiler/passes.nim | 24 ++++++++++-------- compiler/reorder.nim | 13 +++++----- compiler/rodwrite.nim | 43 ++++++++++++++++--------------- compiler/semfold.nim | 20 +++++---------- 6 files changed, 82 insertions(+), 99 deletions(-) diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index 1318b67a70..c2e349c4ee 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -113,16 +113,16 @@ when false: localError(pkg.info, "package name must be an identifier or string literal") result = "" -proc getModuleName*(n: PNode): string = +proc getModuleName*(conf: ConfigRef; n: PNode): string = # This returns a short relative module name without the nim extension # e.g. like "system", "importer" or "somepath/module" # The proc won't perform any checks that the path is actually valid case n.kind of nkStrLit, nkRStrLit, nkTripleStrLit: try: - result = pathSubs(n.strVal, n.info.toFullPath().splitFile().dir) + result = pathSubs(conf, n.strVal, n.info.toFullPath().splitFile().dir) except ValueError: - localError(n.info, "invalid path: " & n.strVal) + localError(conf, n.info, "invalid path: " & n.strVal) result = n.strVal of nkIdent: result = n.ident.s @@ -137,7 +137,7 @@ proc getModuleName*(n: PNode): string = n.sons[0] = n.sons[1] n.sons[1] = n.sons[2] n.sons.setLen(2) - return getModuleName(n.sons[0]) + return getModuleName(conf, n.sons[0]) when false: if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$": if n0.kind == nkIdent and n0.ident.s == "/": @@ -146,7 +146,7 @@ proc getModuleName*(n: PNode): string = localError(n.info, "only '/' supported with $package notation") result = "" else: - let modname = getModuleName(n[2]) + let modname = getModuleName(conf, n[2]) if $n1 == "std": template attempt(a) = let x = addFileExt(a, "nim") @@ -155,7 +155,7 @@ proc getModuleName*(n: PNode): string = attempt(options.libpath / candidate / modname) # hacky way to implement 'x / y /../ z': - result = getModuleName(n1) + result = getModuleName(conf, n1) result.add renderTree(n0, {renderNoComments}) result.add modname of nkPrefix: @@ -169,19 +169,19 @@ proc getModuleName*(n: PNode): string = of nkDotExpr: result = renderTree(n, {renderNoComments}).replace(".", "/") of nkImportAs: - result = getModuleName(n.sons[0]) + result = getModuleName(conf, n.sons[0]) else: - localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree) + localError(conf, n.info, "invalid module name: '$1'" % n.renderTree) result = "" -proc checkModuleName*(n: PNode; doLocalError=true): FileIndex = +proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex = # This returns the full canonical path for a given module import - let modulename = n.getModuleName - let fullPath = findModule(modulename, n.info.toFullPath) + let modulename = getModuleName(conf, n) + let fullPath = findModule(conf, modulename, n.info.toFullPath) if fullPath.len == 0: if doLocalError: let m = if modulename.len > 0: modulename else: $n - localError(n.info, errCannotOpenFile, m) + localError(conf, n.info, "cannot open file: " & m) result = InvalidFileIDX else: - result = fullPath.fileInfoIdx + result = fileInfoIdx(conf, fullPath) diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index 8ec4d3c0dd..6cb675ed82 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -12,27 +12,10 @@ import ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer -proc toBitSet*(s: PNode, b: var TBitSet) - # this function is used for case statement checking: -proc overlap*(a, b: PNode): bool -proc inSet*(s: PNode, elem: PNode): bool -proc someInSet*(s: PNode, a, b: PNode): bool -proc emptyRange*(a, b: PNode): bool -proc setHasRange*(s: PNode): bool - # returns true if set contains a range (needed by the code generator) - # these are used for constant folding: -proc unionSets*(a, b: PNode): PNode -proc diffSets*(a, b: PNode): PNode -proc intersectSets*(a, b: PNode): PNode -proc symdiffSets*(a, b: PNode): PNode -proc containsSets*(a, b: PNode): bool -proc equalSets*(a, b: PNode): bool -proc cardSet*(a: PNode): BiggestInt -# implementation - -proc inSet(s: PNode, elem: PNode): bool = +proc inSet*(s: PNode, elem: PNode): bool = + assert s.kind == nkCurly if s.kind != nkCurly: - internalError(s.info, "inSet") + #internalError(s.info, "inSet") return false for i in countup(0, sonsLen(s) - 1): if s.sons[i].kind == nkRange: @@ -44,7 +27,7 @@ proc inSet(s: PNode, elem: PNode): bool = return true result = false -proc overlap(a, b: PNode): bool = +proc overlap*(a, b: PNode): bool = if a.kind == nkRange: if b.kind == nkRange: # X..Y and C..D overlap iff (X <= D and C <= Y) @@ -58,10 +41,11 @@ proc overlap(a, b: PNode): bool = else: result = sameValue(a, b) -proc someInSet(s: PNode, a, b: PNode): bool = +proc someInSet*(s: PNode, a, b: PNode): bool = # checks if some element of a..b is in the set s + assert s.kind == nkCurly if s.kind != nkCurly: - internalError(s.info, "SomeInSet") + #internalError(s.info, "SomeInSet") return false for i in countup(0, sonsLen(s) - 1): if s.sons[i].kind == nkRange: @@ -74,7 +58,7 @@ proc someInSet(s: PNode, a, b: PNode): bool = return true result = false -proc toBitSet(s: PNode, b: var TBitSet) = +proc toBitSet*(s: PNode, b: var TBitSet) = var first, j: BiggestInt first = firstOrd(s.typ.sons[0]) bitSetInit(b, int(getSize(s.typ))) @@ -87,7 +71,7 @@ proc toBitSet(s: PNode, b: var TBitSet) = else: bitSetIncl(b, getOrdValue(s.sons[i]) - first) -proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode = +proc toTreeSet*(s: TBitSet, settype: PType, info: TLineInfo): PNode = var a, b, e, first: BiggestInt # a, b are interval borders elemType: PType @@ -128,18 +112,18 @@ template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} = op(x, y) result = toTreeSet(x, a.typ, a.info) -proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion) -proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff) -proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect) -proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff) +proc unionSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion) +proc diffSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff) +proc intersectSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect) +proc symdiffSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff) -proc containsSets(a, b: PNode): bool = +proc containsSets*(a, b: PNode): bool = var x, y: TBitSet toBitSet(a, x) toBitSet(b, y) result = bitSetContains(x, y) -proc equalSets(a, b: PNode): bool = +proc equalSets*(a, b: PNode): bool = var x, y: TBitSet toBitSet(a, x) toBitSet(b, y) @@ -156,20 +140,19 @@ proc deduplicate*(a: PNode): PNode = toBitSet(a, x) result = toTreeSet(x, a.typ, a.info) -proc cardSet(a: PNode): BiggestInt = +proc cardSet*(a: PNode): BiggestInt = var x: TBitSet toBitSet(a, x) result = bitSetCard(x) -proc setHasRange(s: PNode): bool = +proc setHasRange*(s: PNode): bool = + assert s.kind == nkCurly if s.kind != nkCurly: - internalError(s.info, "SetHasRange") return false for i in countup(0, sonsLen(s) - 1): if s.sons[i].kind == nkRange: return true result = false -proc emptyRange(a, b: PNode): bool = +proc emptyRange*(a, b: PNode): bool = result = not leValue(a, b) # a > b iff not (a <= b) - diff --git a/compiler/passes.nim b/compiler/passes.nim index b104cd132a..931bcc04bc 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -13,7 +13,8 @@ import strutils, options, ast, astalgo, llstream, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, - nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder, rod + nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder, rod, + configuration type @@ -57,11 +58,11 @@ var # implementation -proc skipCodegen*(n: PNode): bool {.inline.} = +proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} = # can be used by codegen passes to determine whether they should do # something with `n`. Currently, this ignores `n` and uses the global # error count instead. - result = msgs.gErrorCounter > 0 + result = config.errorCounter > 0 const maxPasses = 10 @@ -139,20 +140,21 @@ proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) = m = gPasses[i].close(graph, a[i], m) a[i] = nil # free the memory here -proc resolveMod(module, relativeTo: string): FileIndex = - let fullPath = findModule(module, relativeTo) +proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex = + let fullPath = findModule(conf, module, relativeTo) if fullPath.len == 0: result = InvalidFileIDX else: - result = fullPath.fileInfoIdx + result = fileInfoIdx(conf, fullPath) -proc processImplicits(implicits: seq[string], nodeKind: TNodeKind, +proc processImplicits(conf: ConfigRef; implicits: seq[string], nodeKind: TNodeKind, a: var TPassContextArray; m: PSym) = # XXX fixme this should actually be relative to the config file! + let gCmdLineInfo = newLineInfo(FileIndex(0), 1, 1) let relativeTo = m.info.toFullPath for module in items(implicits): # implicit imports should not lead to a module importing itself - if m.position != resolveMod(module, relativeTo).int32: + if m.position != resolveMod(conf, module, relativeTo).int32: var importStmt = newNodeI(nodeKind, gCmdLineInfo) var str = newStrNode(nkStrLit, module) str.info = gCmdLineInfo @@ -202,7 +204,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, let filename = fileIdx.toFullPathConsiderDirty s = llStreamOpen(filename, fmRead) if s == nil: - rawMessage(errCannotOpenFile, filename) + rawMessage(graph.config, errCannotOpenFile, filename) return false else: s = stream @@ -214,8 +216,8 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, # modules to include between compilation runs? we'd need to track that # in ROD files. I think we should enable this feature only # for the interactive mode. - processImplicits implicitImports, nkImportStmt, a, module - processImplicits implicitIncludes, nkIncludeStmt, a, module + processImplicits graph.config, implicitImports, nkImportStmt, a, module + processImplicits graph.config, implicitIncludes, nkIncludeStmt, a, module while true: if graph.stopCompile(): break diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 2542a08ea4..d50be1d998 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -1,7 +1,8 @@ import intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils, - sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables + sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables, + configuration type DepN = ref object @@ -151,10 +152,10 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode, for a in n: if a.kind == nkIncludeStmt: for i in 0..= 0'i64 or (res xor b) >= 0'i64) and checkInRange(n, res): - result = newIntNodeT(res, n) + result = newIntNodeT(res, n) proc foldSub*(a, b: BiggestInt, n: PNode): PNode = let res = a -% b @@ -43,7 +39,7 @@ proc foldSub*(a, b: BiggestInt, n: PNode): PNode = proc foldAbs*(a: BiggestInt, n: PNode): PNode = if a != firstOrd(n.typ): result = newIntNodeT(a, n) - + proc foldMod*(a, b: BiggestInt, n: PNode): PNode = if b != 0'i64: result = newIntNodeT(a mod b, n) @@ -81,9 +77,7 @@ proc foldMul*(a, b: BiggestInt, n: PNode): PNode = checkInRange(n, res): return newIntNodeT(res, n) -# implementation - -proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode = +proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode = case skipTypes(n.typ, abstractVarRange).kind of tyInt: result = newIntNode(nkIntLit, intVal) @@ -103,7 +97,7 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode = result.typ = n.typ result.info = n.info -proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = +proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode): PNode = result = newFloatNode(nkFloatLit, floatVal) if skipTypes(n.typ, abstractVarRange).kind == tyFloat: result.typ = getFloatLitType(result) @@ -111,7 +105,7 @@ proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = result.typ = n.typ result.info = n.info -proc newStrNodeT(strVal: string, n: PNode): PNode = +proc newStrNodeT*(strVal: string, n: PNode): PNode = result = newStrNode(nkStrLit, strVal) result.typ = n.typ result.info = n.info @@ -378,7 +372,7 @@ proc getConstIfExpr(c: PSym, n: PNode): PNode = if result == nil: result = getConstExpr(c, it.sons[0]) else: internalError(it.info, "getConstIfExpr()") -proc leValueConv(a, b: PNode): bool = +proc leValueConv*(a, b: PNode): bool = result = false case a.kind of nkCharLit..nkUInt64Lit: From a6e53ec47b92f298d1a71a7fb97099bfed1049eb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 May 2018 14:38:12 +0200 Subject: [PATCH 176/214] semfold compiles again --- compiler/configuration.nim | 8 +- compiler/semfold.nim | 524 +++++++++++++++++++------------------ 2 files changed, 267 insertions(+), 265 deletions(-) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index 452a999648..b9121192cb 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -217,11 +217,11 @@ errXExpectsTypeOrValue: "'$1' expects a type or value", errXExpectsArrayType: "'$1' expects an array type", errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", errExprXAmbiguous: "expression '$1' ambiguous in this context", -errConstantDivisionByZero: "division by zero", +errConstantDivisionByZero: , errOrdinalTypeExpected: "ordinal type expected", errOrdinalOrFloatTypeExpected: "ordinal or float type expected", -errOverOrUnderflow: "over- or underflow", -errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely", +errOverOrUnderflow: , +errCannotEvalXBecauseIncompletelyDefined: , errChrExpectsRange0_255: "'chr' expects an int in the range 0..255", errDynlibRequiresExportc: "'dynlib' requires 'exportc'", errUndeclaredFieldX: "undeclared field: '$1'", @@ -287,7 +287,7 @@ errImplOfXexpected: "implementation of '$1' expected", errNoSymbolToBorrowFromFound: "no symbol to borrow from found", errDiscardValueX: "value of type '$1' has to be discarded", errInvalidDiscard: "statement returns no value that can be discarded", -errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid", +errIllegalConvFromXtoY: , errCannotBindXTwice: "cannot bind parameter '$1' twice", errInvalidOrderInArrayConstructor: "invalid order in array constructor", errInvalidOrderInEnumX: "invalid order in enum '$1'", diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 2417e7f6ed..48a81d1105 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -13,78 +13,16 @@ import strutils, options, ast, astalgo, trees, treetab, nimsets, times, nversion, platform, math, msgs, os, condsyms, idents, renderer, types, - commands, magicsys, modulegraphs + commands, magicsys, modulegraphs, strtabs -proc getConstExpr*(m: PSym, n: PNode): PNode - # evaluates the constant expression or returns nil if it is no constant - # expression -proc evalOp*(m: TMagic, n, a, b, c: PNode): PNode - -proc checkInRange(n: PNode, res: BiggestInt): bool = - if res in firstOrd(n.typ)..lastOrd(n.typ): - result = true - -proc foldAdd(a, b: BiggestInt, n: PNode): PNode = - let res = a +% b - if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and - checkInRange(n, res): - result = newIntNodeT(res, n) - -proc foldSub*(a, b: BiggestInt, n: PNode): PNode = - let res = a -% b - if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and - checkInRange(n, res): - result = newIntNodeT(res, n) - -proc foldAbs*(a: BiggestInt, n: PNode): PNode = - if a != firstOrd(n.typ): - result = newIntNodeT(a, n) - -proc foldMod*(a, b: BiggestInt, n: PNode): PNode = - if b != 0'i64: - result = newIntNodeT(a mod b, n) - -proc foldModU*(a, b: BiggestInt, n: PNode): PNode = - if b != 0'i64: - result = newIntNodeT(a %% b, n) - -proc foldDiv*(a, b: BiggestInt, n: PNode): PNode = - if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64): - result = newIntNodeT(a div b, n) - -proc foldDivU*(a, b: BiggestInt, n: PNode): PNode = - if b != 0'i64: - result = newIntNodeT(a /% b, n) - -proc foldMul*(a, b: BiggestInt, n: PNode): PNode = - let res = a *% b - let floatProd = toBiggestFloat(a) * toBiggestFloat(b) - let resAsFloat = toBiggestFloat(res) - - # Fast path for normal case: small multiplicands, and no info - # is lost in either method. - if resAsFloat == floatProd and checkInRange(n, res): - return newIntNodeT(res, n) - - # Somebody somewhere lost info. Close enough, or way off? Note - # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). - # The difference either is or isn't significant compared to the - # true value (of which floatProd is a good approximation). - - # abs(diff)/abs(prod) <= 1/32 iff - # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" - if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and - checkInRange(n, res): - return newIntNodeT(res, n) - -proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode = +proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode = case skipTypes(n.typ, abstractVarRange).kind of tyInt: result = newIntNode(nkIntLit, intVal) # See bug #6989. 'pred' et al only produce an int literal type if the # original type was 'int', not a distinct int etc. if n.typ.kind == tyInt: - result.typ = getIntLitType(result) + result.typ = getIntLitType(g, result) else: result.typ = n.typ # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ... @@ -97,20 +35,82 @@ proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode = result.typ = n.typ result.info = n.info -proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode): PNode = +proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode = result = newFloatNode(nkFloatLit, floatVal) if skipTypes(n.typ, abstractVarRange).kind == tyFloat: - result.typ = getFloatLitType(result) + result.typ = getFloatLitType(g, result) else: result.typ = n.typ result.info = n.info -proc newStrNodeT*(strVal: string, n: PNode): PNode = +proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode = result = newStrNode(nkStrLit, strVal) result.typ = n.typ result.info = n.info -proc ordinalValToString*(a: PNode): string = +proc getConstExpr*(m: PSym, n: PNode; g: ModuleGraph): PNode + # evaluates the constant expression or returns nil if it is no constant + # expression +proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode + +proc checkInRange(n: PNode, res: BiggestInt): bool = + if res in firstOrd(n.typ)..lastOrd(n.typ): + result = true + +proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = + let res = a +% b + if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and + checkInRange(n, res): + result = newIntNodeT(res, n, g) + +proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = + let res = a -% b + if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and + checkInRange(n, res): + result = newIntNodeT(res, n, g) + +proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode = + if a != firstOrd(n.typ): + result = newIntNodeT(a, n, g) + +proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = + if b != 0'i64: + result = newIntNodeT(a mod b, n, g) + +proc foldModU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = + if b != 0'i64: + result = newIntNodeT(a %% b, n, g) + +proc foldDiv*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = + if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64): + result = newIntNodeT(a div b, n, g) + +proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = + if b != 0'i64: + result = newIntNodeT(a /% b, n, g) + +proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = + let res = a *% b + let floatProd = toBiggestFloat(a) * toBiggestFloat(b) + let resAsFloat = toBiggestFloat(res) + + # Fast path for normal case: small multiplicands, and no info + # is lost in either method. + if resAsFloat == floatProd and checkInRange(n, res): + return newIntNodeT(res, n, g) + + # Somebody somewhere lost info. Close enough, or way off? Note + # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). + # The difference either is or isn't significant compared to the + # true value (of which floatProd is a good approximation). + + # abs(diff)/abs(prod) <= 1/32 iff + # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" + if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and + checkInRange(n, res): + return newIntNodeT(res, n, g) + +proc ordinalValToString*(a: PNode; g: ModuleGraph): string = # because $ has the param ordinal[T], `a` is not necessarily an enum, but an # ordinal var x = getInt(a) @@ -122,14 +122,14 @@ proc ordinalValToString*(a: PNode): string = of tyEnum: var n = t.n for i in countup(0, sonsLen(n) - 1): - if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString") + if n.sons[i].kind != nkSym: internalError(g.config, a.info, "ordinalValToString") var field = n.sons[i].sym if field.position == x: if field.ast == nil: return field.name.s else: return field.ast.strVal - internalError(a.info, "no symbol for ordinal value: " & $x) + internalError(g.config, a.info, "no symbol for ordinal value: " & $x) else: result = $x @@ -148,12 +148,12 @@ proc pickIntRange(a, b: PType): PType = proc isIntRangeOrLit(t: PType): bool = result = isIntRange(t) or isIntLit(t) -proc makeRange(typ: PType, first, last: BiggestInt): PType = +proc makeRange(typ: PType, first, last: BiggestInt; g: ModuleGraph): PType = let minA = min(first, last) let maxA = max(first, last) let lowerNode = newIntNode(nkIntLit, minA) if typ.kind == tyInt and minA == maxA: - result = getIntLitType(lowerNode) + result = getIntLitType(g, lowerNode) elif typ.kind in {tyUint, tyUInt64}: # these are not ordinal types, so you get no subrange type for these: result = typ @@ -165,7 +165,7 @@ proc makeRange(typ: PType, first, last: BiggestInt): PType = result.n = n addSonSkipIntLit(result, skipTypes(typ, {tyRange})) -proc makeRangeF(typ: PType, first, last: BiggestFloat): PType = +proc makeRangeF(typ: PType, first, last: BiggestFloat; g: ModuleGraph): PType = var n = newNode(nkRange) addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float))) addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float))) @@ -175,9 +175,9 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType = proc evalIs(n, a: PNode): PNode = # XXX: This should use the standard isOpImpl - internalAssert a.kind == nkSym and a.sym.kind == skType - internalAssert n.sonsLen == 3 and - n[2].kind in {nkStrLit..nkTripleStrLit, nkType} + #internalAssert a.kind == nkSym and a.sym.kind == skType + #internalAssert n.sonsLen == 3 and + # n[2].kind in {nkStrLit..nkTripleStrLit, nkType} let t1 = a.sym.typ @@ -201,113 +201,113 @@ proc evalIs(n, a: PNode): PNode = result = newIntNode(nkIntLit, ord(match)) result.typ = n.typ -proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = +proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = # b and c may be nil result = nil case m - of mOrd: result = newIntNodeT(getOrdValue(a), n) - of mChr: result = newIntNodeT(getInt(a), n) - of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n) - of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n) - of mNot: result = newIntNodeT(1 - getInt(a), n) - of mCard: result = newIntNodeT(nimsets.cardSet(a), n) - of mBitnotI: result = newIntNodeT(not getInt(a), n) - of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n) + of mOrd: result = newIntNodeT(getOrdValue(a), n, g) + of mChr: result = newIntNodeT(getInt(a), n, g) + of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n, g) + of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g) + of mNot: result = newIntNodeT(1 - getInt(a), n, g) + of mCard: result = newIntNodeT(nimsets.cardSet(a), n, g) + of mBitnotI: result = newIntNodeT(not getInt(a), n, g) + of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n, g) of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr: if a.kind == nkNilLit: - result = newIntNodeT(0, n) + result = newIntNodeT(0, n, g) elif a.kind in {nkStrLit..nkTripleStrLit}: - result = newIntNodeT(len a.strVal, n) + result = newIntNodeT(len a.strVal, n, g) else: - result = newIntNodeT(sonsLen(a), n) # BUGFIX + result = newIntNodeT(sonsLen(a), n, g) of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away of mToFloat, mToBiggestFloat: - result = newFloatNodeT(toFloat(int(getInt(a))), n) + result = newFloatNodeT(toFloat(int(getInt(a))), n, g) # XXX: Hides overflow/underflow - of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n) - of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n) - of mAbsI: result = foldAbs(getInt(a), n) + of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n, g) + of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g) + of mAbsI: result = foldAbs(getInt(a), n, g) of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64: # byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64 - result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n) - of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n) - of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n) - of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n) - of mUnaryLt: result = foldSub(getOrdValue(a), 1, n) - of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n) - of mPred: result = foldSub(getOrdValue(a), getInt(b), n) - of mAddI: result = foldAdd(getInt(a), getInt(b), n) - of mSubI: result = foldSub(getInt(a), getInt(b), n) - of mMulI: result = foldMul(getInt(a), getInt(b), n) + result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n, g) + of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g) + of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g) + of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g) + of mUnaryLt: result = foldSub(getOrdValue(a), 1, n, g) + of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g) + of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g) + of mAddI: result = foldAdd(getInt(a), getInt(b), n, g) + of mSubI: result = foldSub(getInt(a), getInt(b), n, g) + of mMulI: result = foldMul(getInt(a), getInt(b), n, g) of mMinI: - if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n) - else: result = newIntNodeT(getInt(a), n) + if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n, g) + else: result = newIntNodeT(getInt(a), n, g) of mMaxI: - if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n) - else: result = newIntNodeT(getInt(b), n) + if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n, g) + else: result = newIntNodeT(getInt(b), n, g) of mShlI: case skipTypes(n.typ, abstractRange).kind - of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n) - of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n) - of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n) + of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g) + of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g) + of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g) of tyInt64, tyInt, tyUInt..tyUInt64: - result = newIntNodeT(`shl`(getInt(a), getInt(b)), n) - else: internalError(n.info, "constant folding for shl") + result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g) + else: internalError(g.config, n.info, "constant folding for shl") of mShrI: case skipTypes(n.typ, abstractRange).kind - of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n) - of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n) - of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n) + of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n, g) + of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n, g) + of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n, g) of tyInt64, tyInt, tyUInt..tyUInt64: - result = newIntNodeT(`shr`(getInt(a), getInt(b)), n) - else: internalError(n.info, "constant folding for shr") - of mDivI: result = foldDiv(getInt(a), getInt(b), n) - of mModI: result = foldMod(getInt(a), getInt(b), n) - of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n) - of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n) - of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n) + result = newIntNodeT(`shr`(getInt(a), getInt(b)), n, g) + else: internalError(g.config, n.info, "constant folding for shr") + of mDivI: result = foldDiv(getInt(a), getInt(b), n, g) + of mModI: result = foldMod(getInt(a), getInt(b), n, g) + of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g) + of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g) + of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g) of mDivF64: if getFloat(b) == 0.0: - if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n) - elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n) - else: result = newFloatNodeT(Inf, n) + if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n, g) + elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n, g) + else: result = newFloatNodeT(Inf, n, g) else: - result = newFloatNodeT(getFloat(a) / getFloat(b), n) + result = newFloatNodeT(getFloat(a) / getFloat(b), n, g) of mMaxF64: - if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n) - else: result = newFloatNodeT(getFloat(b), n) + if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g) + else: result = newFloatNodeT(getFloat(b), n, g) of mMinF64: - if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n) - else: result = newFloatNodeT(getFloat(a), n) - of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n) + if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n, g) + else: result = newFloatNodeT(getFloat(a), n, g) + of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n, g) of mLtI, mLtB, mLtEnum, mLtCh: - result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n) + result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n, g) of mLeI, mLeB, mLeEnum, mLeCh: - result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n) + result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n, g) of mEqI, mEqB, mEqEnum, mEqCh: - result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n) - of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n) - of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n) - of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n) - of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n) - of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n) - of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n) + result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n, g) + of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n, g) + of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n, g) + of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n, g) + of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n, g) + of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n, g) + of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n, g) of mLtU, mLtU64: - result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n) + result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g) of mLeU, mLeU64: - result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n) - of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n) - of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n) - of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n) - of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n) - of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n) - of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n) - of mModU: result = foldModU(getInt(a), getInt(b), n) - of mDivU: result = foldDivU(getInt(a), getInt(b), n) - of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n) - of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n) + result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g) + of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n, g) + of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n, g) + of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n, g) + of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n, g) + of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n, g) + of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g) + of mModU: result = foldModU(getInt(a), getInt(b), n, g) + of mDivU: result = foldDivU(getInt(a), getInt(b), n, g) + of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n, g) + of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n, g) of mLtSet: - result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n) + result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n, g) of mMulSet: result = nimsets.intersectSets(a, b) result.info = n.info @@ -320,57 +320,57 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mSymDiffSet: result = nimsets.symdiffSets(a, b) result.info = n.info - of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n) - of mInSet: result = newIntNodeT(ord(inSet(a, b)), n) + of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g) + of mInSet: result = newIntNodeT(ord(inSet(a, b)), n, g) of mRepr: # BUGFIX: we cannot eval mRepr here for reasons that I forgot. discard - of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n) + of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n, g) of mBoolToStr: - if getOrdValue(a) == 0: result = newStrNodeT("false", n) - else: result = newStrNodeT("true", n) - of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n) + if getOrdValue(a) == 0: result = newStrNodeT("false", n, g) + else: result = newStrNodeT("true", n, g) + of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n, g) of mCopyStrLast: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), - int(getOrdValue(c))), n) - of mFloatToStr: result = newStrNodeT($getFloat(a), n) + int(getOrdValue(c))), n, g) + of mFloatToStr: result = newStrNodeT($getFloat(a), n, g) of mCStrToStr, mCharToStr: if a.kind == nkBracket: var s = "" for b in a.sons: s.add b.getStrOrChar - result = newStrNodeT(s, n) + result = newStrNodeT(s, n, g) else: - result = newStrNodeT(getStrOrChar(a), n) + result = newStrNodeT(getStrOrChar(a), n, g) of mStrToStr: result = a - of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n) + of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g) of mArrToSeq: result = copyTree(a) result.typ = n.typ of mCompileOption: - result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n) + result = newIntNodeT(ord(commands.testCompileOption(g.config, a.getStr, n.info)), n, g) of mCompileOptionArg: result = newIntNodeT(ord( - testCompileOptionArg(getStr(a), getStr(b), n.info)), n) + testCompileOptionArg(g.config, getStr(a), getStr(b), n.info)), n, g) of mEqProc: result = newIntNodeT(ord( - exprStructuralEquivalent(a, b, strictSymEquality=true)), n) + exprStructuralEquivalent(a, b, strictSymEquality=true)), n, g) else: discard -proc getConstIfExpr(c: PSym, n: PNode): PNode = +proc getConstIfExpr(c: PSym, n: PNode; g: ModuleGraph): PNode = result = nil for i in countup(0, sonsLen(n) - 1): var it = n.sons[i] if it.len == 2: - var e = getConstExpr(c, it.sons[0]) + var e = getConstExpr(c, it.sons[0], g) if e == nil: return nil if getOrdValue(e) != 0: if result == nil: - result = getConstExpr(c, it.sons[1]) + result = getConstExpr(c, it.sons[1], g) if result == nil: return elif it.len == 1: - if result == nil: result = getConstExpr(c, it.sons[0]) - else: internalError(it.info, "getConstIfExpr()") + if result == nil: result = getConstExpr(c, it.sons[0], g) + else: internalError(g.config, it.info, "getConstIfExpr()") proc leValueConv*(a, b: PNode): bool = result = false @@ -379,66 +379,66 @@ proc leValueConv*(a, b: PNode): bool = case b.kind of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int - else: internalError(a.info, "leValueConv") + else: result = false #internalError(a.info, "leValueConv") of nkFloatLit..nkFloat128Lit: case b.kind of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal)) - else: internalError(a.info, "leValueConv") - else: internalError(a.info, "leValueConv") + else: result = false # internalError(a.info, "leValueConv") + else: result = false # internalError(a.info, "leValueConv") -proc magicCall(m: PSym, n: PNode): PNode = +proc magicCall(m: PSym, n: PNode; g: ModuleGraph): PNode = if sonsLen(n) <= 1: return var s = n.sons[0].sym - var a = getConstExpr(m, n.sons[1]) + var a = getConstExpr(m, n.sons[1], g) var b, c: PNode if a == nil: return if sonsLen(n) > 2: - b = getConstExpr(m, n.sons[2]) + b = getConstExpr(m, n.sons[2], g) if b == nil: return if sonsLen(n) > 3: - c = getConstExpr(m, n.sons[3]) + c = getConstExpr(m, n.sons[3], g) if c == nil: return - result = evalOp(s.magic, n, a, b, c) + result = evalOp(s.magic, n, a, b, c, g) -proc getAppType(n: PNode): PNode = +proc getAppType(n: PNode; g: ModuleGraph): PNode = if gGlobalOptions.contains(optGenDynLib): - result = newStrNodeT("lib", n) + result = newStrNodeT("lib", n, g) elif gGlobalOptions.contains(optGenStaticLib): - result = newStrNodeT("staticlib", n) + result = newStrNodeT("staticlib", n, g) elif gGlobalOptions.contains(optGenGuiApp): - result = newStrNodeT("gui", n) + result = newStrNodeT("gui", n, g) else: - result = newStrNodeT("console", n) + result = newStrNodeT("console", n, g) -proc rangeCheck(n: PNode, value: BiggestInt) = +proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) = var err = false if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}: err = value <% firstOrd(n.typ) or value >% lastOrd(n.typ, fixedUnsigned=true) else: err = value < firstOrd(n.typ) or value > lastOrd(n.typ) if err: - localError(n.info, errGenerated, "cannot convert " & $value & + localError(g.config, n.info, "cannot convert " & $value & " to " & typeToString(n.typ)) -proc foldConv*(n, a: PNode; check = false): PNode = +proc foldConv*(n, a: PNode; g: ModuleGraph; check = false): PNode = # XXX range checks? case skipTypes(n.typ, abstractRange).kind of tyInt..tyInt64, tyUInt..tyUInt64: case skipTypes(a.typ, abstractRange).kind of tyFloat..tyFloat64: - result = newIntNodeT(int(getFloat(a)), n) - of tyChar: result = newIntNodeT(getOrdValue(a), n) + result = newIntNodeT(int(getFloat(a)), n, g) + of tyChar: result = newIntNodeT(getOrdValue(a), n, g) else: result = a result.typ = n.typ if check and result.kind in {nkCharLit..nkUInt64Lit}: - rangeCheck(n, result.intVal) + rangeCheck(n, result.intVal, g) of tyFloat..tyFloat64: case skipTypes(a.typ, abstractRange).kind of tyInt..tyInt64, tyEnum, tyBool, tyChar: - result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n) + result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g) else: result = a result.typ = n.typ @@ -448,19 +448,19 @@ proc foldConv*(n, a: PNode; check = false): PNode = result = a result.typ = n.typ -proc getArrayConstr(m: PSym, n: PNode): PNode = +proc getArrayConstr(m: PSym, n: PNode; g: ModuleGraph): PNode = if n.kind == nkBracket: result = n else: - result = getConstExpr(m, n) + result = getConstExpr(m, n, g) if result == nil: result = n -proc foldArrayAccess(m: PSym, n: PNode): PNode = - var x = getConstExpr(m, n.sons[0]) +proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = + var x = getConstExpr(m, n.sons[0], g) if x == nil or x.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyTypeDesc: return - var y = getConstExpr(m, n.sons[1]) + var y = getConstExpr(m, n.sons[1], g) if y == nil: return var idx = getOrdValue(y) @@ -470,24 +470,24 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode = result = x.sons[int(idx)] if result.kind == nkExprColonExpr: result = result.sons[1] else: - localError(n.info, errIndexOutOfBounds) + localError(g.config, n.info, "index out of bounds: " & $n) of nkBracket: idx = idx - x.typ.firstOrd if idx >= 0 and idx < x.len: result = x.sons[int(idx)] - else: localError(n.info, errIndexOutOfBounds) + else: localError(g.config, n.info, "index out of bounds: " & $n) of nkStrLit..nkTripleStrLit: result = newNodeIT(nkCharLit, x.info, n.typ) if idx >= 0 and idx < len(x.strVal): result.intVal = ord(x.strVal[int(idx)]) - elif idx == len(x.strVal): + elif idx == len(x.strVal) and optLaxStrings in gOptions: discard else: - localError(n.info, errIndexOutOfBounds) + localError(g.config, n.info, "index out of bounds: " & $n) else: discard -proc foldFieldAccess(m: PSym, n: PNode): PNode = +proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = # a real field access; proc calls have already been transformed - var x = getConstExpr(m, n.sons[0]) + var x = getConstExpr(m, n.sons[0], g) if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return var field = n.sons[1].sym @@ -501,13 +501,13 @@ proc foldFieldAccess(m: PSym, n: PNode): PNode = if it.sons[0].sym.name.id == field.name.id: result = x.sons[i].sons[1] return - localError(n.info, errFieldXNotFound, field.name.s) + localError(g.config, n.info, "field not found: " & field.name.s) -proc foldConStrStr(m: PSym, n: PNode): PNode = +proc foldConStrStr(m: PSym, n: PNode; g: ModuleGraph): PNode = result = newNodeIT(nkStrLit, n.info, n.typ) result.strVal = "" for i in countup(1, sonsLen(n) - 1): - let a = getConstExpr(m, n.sons[i]) + let a = getConstExpr(m, n.sons[i], g) if a == nil: return nil result.strVal.add(getStrOrChar(a)) @@ -519,7 +519,7 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode = else: result.typ = s.typ -proc getConstExpr(m: PSym, n: PNode): PNode = +proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode = result = nil proc getSrcTimestamp(): DateTime = @@ -539,32 +539,35 @@ proc getConstExpr(m: PSym, n: PNode): PNode = var s = n.sym case s.kind of skEnumField: - result = newIntNodeT(s.position, n) + result = newIntNodeT(s.position, n, g) of skConst: case s.magic - of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n) + of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n, g) of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(), - "yyyy-MM-dd"), n) + "yyyy-MM-dd"), n, g) of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(), - "HH:mm:ss"), n) - of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n) - of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n) - of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n) - of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n) - of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n) - of mAppType: result = getAppType(n) - of mNaN: result = newFloatNodeT(NaN, n) - of mInf: result = newFloatNodeT(Inf, n) - of mNegInf: result = newFloatNodeT(NegInf, n) + "HH:mm:ss"), n, g) + of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n, g) + of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n, g) + of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n, g) + of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n, g) + of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n, g) + of mAppType: result = getAppType(n, g) + of mNaN: result = newFloatNodeT(NaN, n, g) + of mInf: result = newFloatNodeT(Inf, n, g) + of mNegInf: result = newFloatNodeT(NegInf, n, g) of mIntDefine: - if isDefined(s.name): - result = newIntNodeT(lookupSymbol(s.name).parseInt, n) + if isDefined(g.config, s.name.s): + try: + result = newIntNodeT(g.config.symbols[s.name.s].parseInt, n, g) + except ValueError: + localError(g.config, n.info, "expression is not an integer literal") of mStrDefine: - if isDefined(s.name): - result = newStrNodeT(lookupSymbol(s.name), n) + if isDefined(g.config, s.name.s): + result = newStrNodeT(g.config.symbols[s.name.s], n, g) else: result = copyTree(s.ast) - of {skProc, skFunc, skMethod}: + of skProc, skFunc, skMethod: result = n of skType: # XXX gensym'ed symbols can come here and cannot be resolved. This is @@ -584,7 +587,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of nkCharLit..nkNilLit: result = copyNode(n) of nkIfExpr: - result = getConstIfExpr(m, n) + result = getConstIfExpr(m, n, g) of nkCallKinds: if n.sons[0].kind != nkSym: return var s = n.sons[0].sym @@ -597,68 +600,67 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of mSizeOf: var a = n.sons[1] if computeSize(a.typ) < 0: - localError(a.info, errCannotEvalXBecauseIncompletelyDefined, - "sizeof") + localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely") result = nil elif skipTypes(a.typ, typedescInst+{tyRange}).kind in IntegralTypes+NilableTypes+{tySet}: #{tyArray,tyObject,tyTuple}: - result = newIntNodeT(getSize(a.typ), n) + result = newIntNodeT(getSize(a.typ), n, g) else: result = nil # XXX: size computation for complex types is still wrong of mLow: - result = newIntNodeT(firstOrd(n.sons[1].typ), n) + result = newIntNodeT(firstOrd(n.sons[1].typ), n, g) of mHigh: if skipTypes(n.sons[1].typ, abstractVar).kind notin {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: - result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) + result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n, g) else: - var a = getArrayConstr(m, n.sons[1]) + var a = getArrayConstr(m, n.sons[1], g) if a.kind == nkBracket: # we can optimize it away: - result = newIntNodeT(sonsLen(a)-1, n) + result = newIntNodeT(sonsLen(a)-1, n, g) of mLengthOpenArray: - var a = getArrayConstr(m, n.sons[1]) + var a = getArrayConstr(m, n.sons[1], g) if a.kind == nkBracket: # we can optimize it away! This fixes the bug ``len(134)``. - result = newIntNodeT(sonsLen(a), n) + result = newIntNodeT(sonsLen(a), n, g) else: - result = magicCall(m, n) + result = magicCall(m, n, g) of mLengthArray: # It doesn't matter if the argument is const or not for mLengthArray. # This fixes bug #544. - result = newIntNodeT(lengthOrd(n.sons[1].typ), n) + result = newIntNodeT(lengthOrd(n.sons[1].typ), n, g) of mAstToStr: - result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) + result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g) of mConStrStr: - result = foldConStrStr(m, n) + result = foldConStrStr(m, n, g) of mIs: - let a = getConstExpr(m, n[1]) + let a = getConstExpr(m, n[1], g) if a != nil and a.kind == nkSym and a.sym.kind == skType: result = evalIs(n, a) else: - result = magicCall(m, n) + result = magicCall(m, n, g) except OverflowError: - localError(n.info, errOverOrUnderflow) + localError(g.config, n.info, "over- or underflow") except DivByZeroError: - localError(n.info, errConstantDivisionByZero) + localError(g.config, n.info, "division by zero") of nkAddr: - var a = getConstExpr(m, n.sons[0]) + var a = getConstExpr(m, n.sons[0], g) if a != nil: result = n n.sons[0] = a of nkBracket: result = copyTree(n) for i in countup(0, sonsLen(n) - 1): - var a = getConstExpr(m, n.sons[i]) + var a = getConstExpr(m, n.sons[i], g) if a == nil: return nil result.sons[i] = a incl(result.flags, nfAllConst) of nkRange: - var a = getConstExpr(m, n.sons[0]) + var a = getConstExpr(m, n.sons[0], g) if a == nil: return - var b = getConstExpr(m, n.sons[1]) + var b = getConstExpr(m, n.sons[1], g) if b == nil: return result = copyNode(n) addSon(result, a) @@ -666,7 +668,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of nkCurly: result = copyTree(n) for i in countup(0, sonsLen(n) - 1): - var a = getConstExpr(m, n.sons[i]) + var a = getConstExpr(m, n.sons[i], g) if a == nil: return nil result.sons[i] = a incl(result.flags, nfAllConst) @@ -682,45 +684,45 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result = copyTree(n) if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr): for i in countup(0, sonsLen(n) - 1): - var a = getConstExpr(m, n.sons[i].sons[1]) + var a = getConstExpr(m, n.sons[i].sons[1], g) if a == nil: return nil result.sons[i].sons[1] = a else: for i in countup(0, sonsLen(n) - 1): - var a = getConstExpr(m, n.sons[i]) + var a = getConstExpr(m, n.sons[i], g) if a == nil: return nil result.sons[i] = a incl(result.flags, nfAllConst) of nkChckRangeF, nkChckRange64, nkChckRange: - var a = getConstExpr(m, n.sons[0]) + var a = getConstExpr(m, n.sons[0], g) if a == nil: return if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]): result = a # a <= x and x <= b result.typ = n.typ else: - localError(n.info, errGenerated, `%`( - msgKindToString(errIllegalConvFromXtoY), - [typeToString(n.sons[0].typ), typeToString(n.typ)])) + localError(g.config, n.info, + "conversion from $1 to $2 is invalid" % + [typeToString(n.sons[0].typ), typeToString(n.typ)]) of nkStringToCString, nkCStringToString: - var a = getConstExpr(m, n.sons[0]) + var a = getConstExpr(m, n.sons[0], g) if a == nil: return result = a result.typ = n.typ of nkHiddenStdConv, nkHiddenSubConv, nkConv: - var a = getConstExpr(m, n.sons[1]) + var a = getConstExpr(m, n.sons[1], g) if a == nil: return - result = foldConv(n, a, check=n.kind == nkHiddenStdConv) + result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv) of nkCast: - var a = getConstExpr(m, n.sons[1]) + var a = getConstExpr(m, n.sons[1], g) if a == nil: return if n.typ != nil and n.typ.kind in NilableTypes: # we allow compile-time 'cast' for pointer types: result = a result.typ = n.typ - of nkBracketExpr: result = foldArrayAccess(m, n) - of nkDotExpr: result = foldFieldAccess(m, n) + of nkBracketExpr: result = foldArrayAccess(m, n, g) + of nkDotExpr: result = foldFieldAccess(m, n, g) of nkStmtListExpr: if n.len == 2 and n[0].kind == nkComesFrom: - result = getConstExpr(m, n[1]) + result = getConstExpr(m, n[1], g) else: discard From e1a921ce4fe43c0db91c50061769fecb430b3441 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 May 2018 15:05:05 +0200 Subject: [PATCH 177/214] lookups compiles again --- compiler/configuration.nim | 4 +- compiler/lookups.nim | 109 ++++++++++++++++++------------------- compiler/semdata.nim | 48 ++++++++-------- 3 files changed, 80 insertions(+), 81 deletions(-) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index b9121192cb..6b3034d2b5 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -188,7 +188,7 @@ errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlin errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions", errCannotReturnExpr: "current routine cannot return an expression", errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type", -errAttemptToRedefine: "redefinition of '$1'", +errAttemptToRedefine: , errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma", errStmtExpected: "statement expected", errInvalidLabel: "'$1' is no label", @@ -283,7 +283,7 @@ errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar", errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", errImplOfXNotAllowed: "implementation of '$1' is not allowed", -errImplOfXexpected: "implementation of '$1' expected", +errImplOfXexpected: , errNoSymbolToBorrowFromFound: "no symbol to borrow from found", errDiscardValueX: "value of type '$1' has to be discarded", errInvalidDiscard: "statement returns no value that can be discarded", diff --git a/compiler/lookups.nim b/compiler/lookups.nim index e0d6e00983..e161d2e11f 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -11,23 +11,23 @@ import intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread, - renderer, wordrecg, idgen, nimfix.prettybase + renderer, wordrecg, idgen, nimfix.prettybase, configuration, strutils -proc ensureNoMissingOrUnusedSymbols(scope: PScope) +proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) -proc noidentError(n, origin: PNode) = +proc noidentError(conf: ConfigRef; n, origin: PNode) = var m = "" if origin != nil: m.add "in expression '" & origin.renderTree & "': " m.add "identifier expected, but found '" & n.renderTree & "'" - localError(n.info, m) + localError(conf, n.info, m) -proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent = +proc considerQuotedIdent*(conf: ConfigRef; n: PNode, origin: PNode = nil): PIdent = ## Retrieve a PIdent from a PNode, taking into account accent nodes. ## ``origin`` can be nil. If it is not nil, it is used for a better ## error message. template handleError(n, origin: PNode) = - noidentError(n, origin) + noidentError(conf, n, origin) result = getIdent"" case n.kind @@ -36,7 +36,7 @@ proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent = of nkAccQuoted: case n.len of 0: handleError(n, origin) - of 1: result = considerQuotedIdent(n.sons[0], origin) + of 1: result = considerQuotedIdent(conf, n.sons[0], origin) else: var id = "" for i in 0.. n.ident else: result = nil of oimSelfModule: - result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n) + result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config) of oimOtherModule: - result = nextIdentIter(o.it, o.m.tab).skipAlias(n) + result = nextIdentIter(o.it, o.m.tab).skipAlias(n, c.config) of oimSymChoice: if o.symChoiceIndex < sonsLen(n): result = n.sons[o.symChoiceIndex].sym @@ -430,19 +427,19 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = o.mode = oimSymChoiceLocalLookup o.scope = c.currentScope result = firstIdentExcluding(o.it, o.scope.symbols, - n.sons[0].sym.name, o.inSymChoice).skipAlias(n) + n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config) while result == nil: o.scope = o.scope.parent if o.scope == nil: break result = firstIdentExcluding(o.it, o.scope.symbols, - n.sons[0].sym.name, o.inSymChoice).skipAlias(n) + n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config) of oimSymChoiceLocalLookup: - result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n) + result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n, c.config) while result == nil: o.scope = o.scope.parent if o.scope == nil: break result = firstIdentExcluding(o.it, o.scope.symbols, - n.sons[0].sym.name, o.inSymChoice).skipAlias(n) + n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config) if result != nil and result.kind == skStub: loadStub(result) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index fc0488814c..6f7a48dae2 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -14,7 +14,7 @@ import wordrecg, ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef, - modulegraphs + modulegraphs, configuration type TOptionEntry* = object # entries to put on a stack for pragma parsing @@ -139,6 +139,8 @@ type # would otherwise fail. runnableExamples*: PNode +template config*(c: PContext): ConfigRef = c.graph.config + proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = result.genericSym = s result.inst = inst @@ -164,7 +166,7 @@ proc pushOwner*(c: PContext; owner: PSym) = proc popOwner*(c: PContext) = var length = len(c.graph.owners) if length > 0: setLen(c.graph.owners, length - 1) - else: internalError("popOwner") + else: internalError(c.config, "popOwner") proc lastOptionEntry*(c: PContext): POptionEntry = result = c.optionStack[^1] @@ -200,19 +202,19 @@ proc considerGenSyms*(c: PContext; n: PNode) = for i in 0.. Date: Fri, 11 May 2018 13:07:16 +0200 Subject: [PATCH 178/214] guards.nim does compile --- compiler/configuration.nim | 6 +- compiler/extccomp.nim | 2 +- compiler/guards.nim | 240 ++++++++++++++++++----------------- compiler/msgs.nim | 4 +- compiler/nimfix/pretty.nim | 25 ++-- compiler/options.nim | 12 +- compiler/packagehandling.nim | 23 ++-- compiler/parampatterns.nim | 53 ++++---- compiler/rodread.nim | 2 +- compiler/rodwrite.nim | 2 +- compiler/sempass2.nim | 47 ++++--- compiler/semtypinst.nim | 43 +++---- compiler/writetracking.nim | 12 +- 13 files changed, 241 insertions(+), 230 deletions(-) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index 6b3034d2b5..20003bb2ee 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -267,7 +267,7 @@ errSetTooBig: "set is too large", errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal", errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects", errInheritanceOnlyWithEnums: "inheritance only works with an enum", -errIllegalRecursionInTypeX: "illegal recursion in type '$1'", +errIllegalRecursionInTypeX:, errCannotInstantiateX: "cannot instantiate: '$1'", errExprHasNoAddress: "expression has no address", errXStackEscape: "address of '$1' may not escape its stack frame", @@ -307,7 +307,7 @@ errDefaultArgumentInvalid: "default argument invalid", errNamedParamHasToBeIdent: "named parameter has to be an identifier", errNoReturnTypeForX: "no return type allowed for $1", errConvNeedsOneArg: "a type conversion needs exactly one argument", -errInvalidPragmaX: "invalid pragma: $1", +errInvalidPragmaX: , errXNotAllowedHere: "$1 not allowed here", errInvalidControlFlowX: "invalid control flow: $1", errXisNoType: "invalid type: '$1'", @@ -345,7 +345,7 @@ errNewSectionExpected: "new section expected", errWhitespaceExpected: "whitespace expected, got '$1'", errXisNoValidIndexFile: "'$1' is no valid index file", errCannotRenderX: "cannot render reStructuredText element '$1'", -errVarVarTypeNotAllowed: "type 'var var' is not allowed", +errVarVarTypeNotAllowed: , errInstantiateXExplicitly: "instantiate '$1' explicitly", errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 388bb9c9e0..bab612835f 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -613,7 +613,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}: return false - var hashFile = toGeneratedFile(conf, cfile.cname.withPackageName, "sha1") + var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1") var currentHash = footprint(conf, cfile) var f: File if open(f, hashFile, fmRead): diff --git a/compiler/guards.nim b/compiler/guards.nim index 94af5202d1..9e826b98fc 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -10,7 +10,7 @@ ## This module implements the 'implies' relation for guards. import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents, - saturate + saturate, modulegraphs, options, configuration const someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, @@ -83,18 +83,25 @@ proc isLetLocation(m: PNode, isApprox: bool): bool = proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true) -let - opLe = createMagic("<=", mLeI) - opLt = createMagic("<", mLtI) - opAnd = createMagic("and", mAnd) - opOr = createMagic("or", mOr) - opIsNil = createMagic("isnil", mIsNil) - opEq = createMagic("==", mEqI) - opAdd = createMagic("+", mAddI) - opSub = createMagic("-", mSubI) - opMul = createMagic("*", mMulI) - opDiv = createMagic("div", mDivI) - opLen = createMagic("len", mLengthSeq) +type + Operators* = object + opNot, opContains, opLe, opLt, opAnd, opOr, opIsNil, opEq: PSym + opAdd, opSub, opMul, opDiv, opLen: PSym + +proc initOperators*(g: ModuleGraph): Operators = + result.opLe = createMagic(g, "<=", mLeI) + result.opLt = createMagic(g, "<", mLtI) + result.opAnd = createMagic(g, "and", mAnd) + result.opOr = createMagic(g, "or", mOr) + result.opIsNil = createMagic(g, "isnil", mIsNil) + result.opEq = createMagic(g, "==", mEqI) + result.opAdd = createMagic(g, "+", mAddI) + result.opSub = createMagic(g, "-", mSubI) + result.opMul = createMagic(g, "*", mMulI) + result.opDiv = createMagic(g, "div", mDivI) + result.opLen = createMagic(g, "len", mLengthSeq) + result.opNot = createMagic(g, "not", mNot) + result.opContains = createMagic(g, "contains", mInSet) proc swapArgs(fact: PNode, newOp: PSym): PNode = result = newNodeI(nkCall, fact.info, 3) @@ -102,16 +109,16 @@ proc swapArgs(fact: PNode, newOp: PSym): PNode = result.sons[1] = fact.sons[2] result.sons[2] = fact.sons[1] -proc neg(n: PNode): PNode = +proc neg(n: PNode; o: Operators): PNode = if n == nil: return nil case n.getMagic of mNot: result = n.sons[1] of someLt: # not (a < b) == a >= b == b <= a - result = swapArgs(n, opLe) + result = swapArgs(n, o.opLe) of someLe: - result = swapArgs(n, opLt) + result = swapArgs(n, o.opLt) of mInSet: if n.sons[1].kind != nkCurly: return nil let t = n.sons[2].typ.skipTypes(abstractInst) @@ -133,11 +140,11 @@ proc neg(n: PNode): PNode = of mOr: # not (a or b) --> not a and not b let - a = n.sons[1].neg - b = n.sons[2].neg + a = n.sons[1].neg(o) + b = n.sons[2].neg(o) if a != nil and b != nil: result = newNodeI(nkCall, n.info, 3) - result.sons[0] = newSymNode(opAnd) + result.sons[0] = newSymNode(o.opAnd) result.sons[1] = a result.sons[2] = b elif a != nil: @@ -147,7 +154,7 @@ proc neg(n: PNode): PNode = else: # leave not (a == 4) as it is result = newNodeI(nkCall, n.info, 2) - result.sons[0] = newSymNode(opNot) + result.sons[0] = newSymNode(o.opNot) result.sons[1] = n proc buildCall(op: PSym; a: PNode): PNode = @@ -181,7 +188,7 @@ proc `|div|`(a, b: PNode): PNode = if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal div b.intVal else: result.floatVal = a.floatVal / b.floatVal -proc negate(a, b, res: PNode): PNode = +proc negate(a, b, res: PNode; o: Operators): PNode = if b.kind in {nkCharLit..nkUInt64Lit} and b.intVal != low(BiggestInt): var b = copyNode(b) b.intVal = -b.intVal @@ -189,11 +196,11 @@ proc negate(a, b, res: PNode): PNode = b.intVal = b.intVal |+| a.intVal result = b else: - result = buildCall(opAdd, a, b) + result = buildCall(o.opAdd, a, b) elif b.kind in {nkFloatLit..nkFloat64Lit}: var b = copyNode(b) b.floatVal = -b.floatVal - result = buildCall(opAdd, a, b) + result = buildCall(o.opAdd, a, b) else: result = res @@ -205,7 +212,7 @@ proc lowBound*(x: PNode): PNode = result = nkIntLit.newIntNode(firstOrd(x.typ)) result.info = x.info -proc highBound*(x: PNode): PNode = +proc highBound*(x: PNode; o: Operators): PNode = let typ = x.typ.skipTypes(abstractInst) result = if typ.kind == tyArray: nkIntLit.newIntNode(lastOrd(typ)) @@ -213,23 +220,23 @@ proc highBound*(x: PNode): PNode = x.sym.kind == skConst: nkIntLit.newIntNode(x.sym.ast.len-1) else: - opAdd.buildCall(opLen.buildCall(x), minusOne()) + o.opAdd.buildCall(o.opLen.buildCall(x), minusOne()) result.info = x.info -proc reassociation(n: PNode): PNode = +proc reassociation(n: PNode; o: Operators): PNode = result = n # (foo+5)+5 --> foo+10; same for '*' case result.getMagic of someAdd: if result[2].isValue and result[1].getMagic in someAdd and result[1][2].isValue: - result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2]) + result = o.opAdd.buildCall(result[1][1], result[1][2] |+| result[2]) if result[2].intVal == 0: result = result[1] of someMul: if result[2].isValue and result[1].getMagic in someMul and result[1][2].isValue: - result = opMul.buildCall(result[1][1], result[1][2] |*| result[2]) + result = o.opMul.buildCall(result[1][1], result[1][2] |*| result[2]) if result[2].intVal == 1: result = result[1] elif result[2].intVal == 0: @@ -243,12 +250,12 @@ proc pred(n: PNode): PNode = else: result = n -proc canon*(n: PNode): PNode = +proc canon*(n: PNode; o: Operators): PNode = # XXX for now only the new code in 'semparallel' uses this if n.safeLen >= 1: result = shallowCopy(n) for i in 0 ..< n.len: - result.sons[i] = canon(n.sons[i]) + result.sons[i] = canon(n.sons[i], o) elif n.kind == nkSym and n.sym.kind == skLet and n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin + someMax + someHigh + {mUnaryLt} + someSub + someLen + someDiv): @@ -263,24 +270,24 @@ proc canon*(n: PNode): PNode = # (4 + foo) + 2 --> (foo + 4) + 2 of someHigh: # high == len+(-1) - result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne()) + result = o.opAdd.buildCall(o.opLen.buildCall(result[1]), minusOne()) of mUnaryLt: - result = buildCall(opAdd, result[1], minusOne()) + result = buildCall(o.opAdd, result[1], minusOne()) of someSub: # x - 4 --> x + (-4) - result = negate(result[1], result[2], result) + result = negate(result[1], result[2], result, o) of someLen: - result.sons[0] = opLen.newSymNode + result.sons[0] = o.opLen.newSymNode of someLt: # x < y same as x <= y-1: - let y = n[2].canon + let y = n[2].canon(o) let p = pred(y) - let minus = if p != y: p else: opAdd.buildCall(y, minusOne()).canon - result = opLe.buildCall(n[1].canon, minus) + let minus = if p != y: p else: o.opAdd.buildCall(y, minusOne()).canon(o) + result = o.opLe.buildCall(n[1].canon(o), minus) else: discard result = skipConv(result) - result = reassociation(result) + result = reassociation(result, o) # most important rule: (x-4) <= a.len --> x <= a.len+4 case result.getMagic of someLe: @@ -291,10 +298,10 @@ proc canon*(n: PNode): PNode = case x.getMagic of someSub: result = buildCall(result[0].sym, x[1], - reassociation(opAdd.buildCall(y, x[2]))) + reassociation(o.opAdd.buildCall(y, x[2]), o)) of someAdd: # Rule A: - let plus = negate(y, x[2], nil).reassociation + let plus = negate(y, x[2], nil, o).reassociation(o) if plus != nil: result = buildCall(result[0].sym, x[1], plus) else: discard elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and @@ -303,9 +310,9 @@ proc canon*(n: PNode): PNode = case y.getMagic of someSub: result = buildCall(result[0].sym, y[1], - reassociation(opAdd.buildCall(x, y[2]))) + reassociation(o.opAdd.buildCall(x, y[2]), o)) of someAdd: - let plus = negate(x, y[2], nil).reassociation + let plus = negate(x, y[2], nil, o).reassociation(o) # ensure that Rule A will not trigger afterwards with the # additional 'not isLetLocation' constraint: if plus != nil and not isLetLocation(x, true): @@ -323,15 +330,15 @@ proc canon*(n: PNode): PNode = result.sons[2] = y[1] else: discard -proc `+@`*(a: PNode; b: BiggestInt): PNode = - canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a) +#proc `+@`*(a: PNode; b: BiggestInt): PNode = +# canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a) -proc usefulFact(n: PNode): PNode = +proc usefulFact(n: PNode; o: Operators): PNode = case n.getMagic of someEq: if skipConv(n.sons[2]).kind == nkNilLit and ( isLetLocation(n.sons[1], false) or isVar(n.sons[1])): - result = opIsNil.buildCall(n.sons[1]) + result = o.opIsNil.buildCall(n.sons[1]) else: if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true): # XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1' @@ -351,11 +358,11 @@ proc usefulFact(n: PNode): PNode = result = n of mAnd: let - a = usefulFact(n.sons[1]) - b = usefulFact(n.sons[2]) + a = usefulFact(n.sons[1], o) + b = usefulFact(n.sons[2], o) if a != nil and b != nil: result = newNodeI(nkCall, n.info, 3) - result.sons[0] = newSymNode(opAnd) + result.sons[0] = newSymNode(o.opAnd) result.sons[1] = a result.sons[2] = b elif a != nil: @@ -363,9 +370,9 @@ proc usefulFact(n: PNode): PNode = elif b != nil: result = b of mNot: - let a = usefulFact(n.sons[1]) + let a = usefulFact(n.sons[1], o) if a != nil: - result = a.neg + result = a.neg(o) of mOr: # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything # with that knowledge... @@ -374,14 +381,14 @@ proc usefulFact(n: PNode): PNode = # (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2)) # not (x != 3 and y != 2) let - a = usefulFact(n.sons[1]).neg - b = usefulFact(n.sons[2]).neg + a = usefulFact(n.sons[1], o).neg(o) + b = usefulFact(n.sons[2], o).neg(o) if a != nil and b != nil: result = newNodeI(nkCall, n.info, 3) - result.sons[0] = newSymNode(opAnd) + result.sons[0] = newSymNode(o.opAnd) result.sons[1] = a result.sons[2] = b - result = result.neg + result = result.neg(o) elif n.kind == nkSym and n.sym.kind == skLet: # consider: # let a = 2 < x @@ -389,32 +396,34 @@ proc usefulFact(n: PNode): PNode = # ... # We make can easily replace 'a' by '2 < x' here: if n.sym.ast != nil: - result = usefulFact(n.sym.ast) + result = usefulFact(n.sym.ast, o) elif n.kind == nkStmtListExpr: - result = usefulFact(n.lastSon) + result = usefulFact(n.lastSon, o) type - TModel* = seq[PNode] # the "knowledge base" + TModel* = object + s: seq[PNode] # the "knowledge base" + o: Operators proc addFact*(m: var TModel, nn: PNode) = - let n = usefulFact(nn) - if n != nil: m.add n + let n = usefulFact(nn, m.o) + if n != nil: m.s.add n proc addFactNeg*(m: var TModel, n: PNode) = - let n = n.neg + let n = n.neg(m.o) if n != nil: addFact(m, n) -proc canonOpr(opr: PSym): PSym = - case opr.magic - of someEq: result = opEq - of someLe: result = opLe - of someLt: result = opLt - of someLen: result = opLen - of someAdd: result = opAdd - of someSub: result = opSub - of someMul: result = opMul - of someDiv: result = opDiv - else: result = opr +proc sameOpr(a, b: PSym): bool = + case a.magic + of someEq: result = b.magic in someEq + of someLe: result = b.magic in someLe + of someLt: result = b.magic in someLt + of someLen: result = b.magic in someLen + of someAdd: result = b.magic in someAdd + of someSub: result = b.magic in someSub + of someMul: result = b.magic in someMul + of someDiv: result = b.magic in someDiv + else: result = a == b proc sameTree*(a, b: PNode): bool = result = false @@ -425,7 +434,7 @@ proc sameTree*(a, b: PNode): bool = of nkSym: result = a.sym == b.sym if not result and a.sym.magic != mNone: - result = a.sym.magic == b.sym.magic or canonOpr(a.sym) == canonOpr(b.sym) + result = a.sym.magic == b.sym.magic or sameOpr(a.sym, b.sym) of nkIdent: result = a.ident.id == b.ident.id of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal @@ -462,8 +471,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) = # The same mechanism could be used for more complex data stored on the heap; # procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we # could CSE these expressions then and help C's optimizer. - for i in 0..high(m): - if m[i] != nil and m[i].hasSubTree(n): m[i] = nil + for i in 0..high(m.s): + if m.s[i] != nil and m.s[i].hasSubTree(n): m.s[i] = nil proc valuesUnequal(a, b: PNode): bool = if a.isValue and b.isValue: @@ -486,7 +495,7 @@ proc impliesEq(fact, eq: PNode): TImplication = if sameTree(fact.sons[2], eq.sons[loc]) and isValue(eq.sons[val]): if inSet(fact.sons[1], eq.sons[val]): result = impYes else: result = impNo - of mNot, mOr, mAnd: internalError(eq.info, "impliesEq") + of mNot, mOr, mAnd: assert(false, "impliesEq") else: discard proc leImpliesIn(x, c, aSet: PNode): TImplication = @@ -549,7 +558,7 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication = elif sameTree(fact.sons[2], loc): # 4 < x --> 3 <= x result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet) - of mNot, mOr, mAnd: internalError(loc.info, "impliesIn") + of mNot, mOr, mAnd: assert(false, "impliesIn") else: discard proc valueIsNil(n: PNode): TImplication = @@ -567,11 +576,11 @@ proc impliesIsNil(fact, eq: PNode): TImplication = result = valueIsNil(fact.sons[2].skipConv) elif sameTree(fact.sons[2], eq.sons[1]): result = valueIsNil(fact.sons[1].skipConv) - of mNot, mOr, mAnd: internalError(eq.info, "impliesIsNil") + of mNot, mOr, mAnd: assert(false, "impliesIsNil") else: discard proc impliesGe(fact, x, c: PNode): TImplication = - internalAssert isLocation(x) + assert isLocation(x) case fact.sons[0].sym.magic of someEq: if sameTree(fact.sons[1], x): @@ -603,7 +612,7 @@ proc impliesGe(fact, x, c: PNode): TImplication = # fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3 if isValue(fact.sons[1]) and isValue(c): if leValue(c, fact.sons[1]): result = impYes - of mNot, mOr, mAnd: internalError(x.info, "impliesGe") + of mNot, mOr, mAnd: assert(false, "impliesGe") else: discard proc impliesLe(fact, x, c: PNode): TImplication = @@ -643,7 +652,7 @@ proc impliesLe(fact, x, c: PNode): TImplication = if isValue(fact.sons[1]) and isValue(c): if leValue(c, fact.sons[1].pred): result = impNo - of mNot, mOr, mAnd: internalError(x.info, "impliesLe") + of mNot, mOr, mAnd: assert(false, "impliesLe") else: discard proc impliesLt(fact, x, c: PNode): TImplication = @@ -707,14 +716,14 @@ proc factImplies(fact, prop: PNode): TImplication = proc doesImply*(facts: TModel, prop: PNode): TImplication = assert prop.kind in nkCallKinds - for f in facts: + for f in facts.s: # facts can be invalidated, in which case they are 'nil': if not f.isNil: result = f.factImplies(prop) if result != impUnknown: return -proc impliesNotNil*(facts: TModel, arg: PNode): TImplication = - result = doesImply(facts, opIsNil.buildCall(arg).neg) +proc impliesNotNil*(m: TModel, arg: PNode): TImplication = + result = doesImply(m, m.o.opIsNil.buildCall(arg).neg(m.o)) proc simpleSlice*(a, b: PNode): BiggestInt = # returns 'c' if a..b matches (i+c)..(i+c), -1 otherwise. (i)..(i) is matched @@ -817,20 +826,20 @@ proc ple(m: TModel; a, b: PNode): TImplication = if a.getMagic in someMul and a[2].isValue and a[1].getMagic in someDiv and a[1][2].isValue: # simplify (x div 4) * 2 <= y to x div (c div d) <= y - if ple(m, buildCall(opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes: + if ple(m, buildCall(m.o.opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes: return impYes # x*3 + x == x*4. It follows that: # x*3 + y <= x*4 if y <= x and 3 <= 4 if a =~ x*dc + y and b =~ x2*ec: if sameTree(x, x2): - let ec1 = opAdd.buildCall(ec, minusOne()) + let ec1 = m.o.opAdd.buildCall(ec, minusOne()) if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? x: return impYes elif a =~ x*dc and b =~ x2*ec + y: #echo "BUG cam ehrer e ", a, " <=? ", b if sameTree(x, x2): - let ec1 = opAdd.buildCall(ec, minusOne()) + let ec1 = m.o.opAdd.buildCall(ec, minusOne()) if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? zero(): return impYes @@ -863,9 +872,9 @@ proc ple(m: TModel; a, b: PNode): TImplication = # use the knowledge base: return pleViaModel(m, a, b) - #return doesImply(m, opLe.buildCall(a, b)) + #return doesImply(m, o.opLe.buildCall(a, b)) -type TReplacements = seq[tuple[a,b: PNode]] +type TReplacements = seq[tuple[a, b: PNode]] proc replaceSubTree(n, x, by: PNode): PNode = if sameTree(n, x): @@ -883,11 +892,11 @@ proc applyReplacements(n: PNode; rep: TReplacements): PNode = proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication = # now check for inferrable facts: a <= b and b <= c implies a <= c - for i in 0..m.high: - let fact = m[i] + for i in 0..m.s.high: + let fact = m.s[i] if fact != nil and fact.getMagic in someLe: # mark as used: - m[i] = nil + m.s[i] = nil # i <= len-100 # i <=? len-1 # --> true if (len-100) <= (len-1) @@ -919,7 +928,7 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication = proc pleViaModel(model: TModel; aa, bb: PNode): TImplication = # compute replacements: var replacements: TReplacements = @[] - for fact in model: + for fact in model.s: if fact != nil and fact.getMagic in someEq: let a = fact[1] let b = fact[2] @@ -929,12 +938,13 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication = var a = aa var b = bb if replacements.len > 0: - m = @[] + m.s = @[] + m.o = model.o # make the other facts consistent: - for fact in model: + for fact in model.s: if fact != nil and fact.getMagic notin someEq: # XXX 'canon' should not be necessary here, but it is - m.add applyReplacements(fact, replacements).canon + m.s.add applyReplacements(fact, replacements).canon(m.o) a = applyReplacements(aa, replacements) b = applyReplacements(bb, replacements) else: @@ -943,31 +953,31 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication = result = pleViaModelRec(m, a, b) proc proveLe*(m: TModel; a, b: PNode): TImplication = - let x = canon(opLe.buildCall(a, b)) + let x = canon(m.o.opLe.buildCall(a, b), m.o) #echo "ROOT ", renderTree(x[1]), " <=? ", renderTree(x[2]) result = ple(m, x[1], x[2]) if result == impUnknown: # try an alternative: a <= b iff not (b < a) iff not (b+1 <= a): - let y = canon(opLe.buildCall(opAdd.buildCall(b, one()), a)) + let y = canon(m.o.opLe.buildCall(m.o.opAdd.buildCall(b, one()), a), m.o) result = ~ple(m, y[1], y[2]) proc addFactLe*(m: var TModel; a, b: PNode) = - m.add canon(opLe.buildCall(a, b)) + m.s.add canon(m.o.opLe.buildCall(a, b), m.o) proc settype(n: PNode): PType = result = newType(tySet, n.typ.owner) addSonSkipIntLit(result, n.typ) -proc buildOf(it, loc: PNode): PNode = +proc buildOf(it, loc: PNode; o: Operators): PNode = var s = newNodeI(nkCurly, it.info, it.len-1) s.typ = settype(loc) for i in 0..it.len-2: s.sons[i] = it.sons[i] result = newNodeI(nkCall, it.info, 3) - result.sons[0] = newSymNode(opContains) + result.sons[0] = newSymNode(o.opContains) result.sons[1] = s result.sons[2] = loc -proc buildElse(n: PNode): PNode = +proc buildElse(n: PNode; o: Operators): PNode = var s = newNodeIT(nkCurly, n.info, settype(n.sons[0])) for i in 1..n.len-2: let branch = n.sons[i] @@ -975,23 +985,23 @@ proc buildElse(n: PNode): PNode = for j in 0..branch.len-2: s.add(branch.sons[j]) result = newNodeI(nkCall, n.info, 3) - result.sons[0] = newSymNode(opContains) + result.sons[0] = newSymNode(o.opContains) result.sons[1] = s result.sons[2] = n.sons[0] proc addDiscriminantFact*(m: var TModel, n: PNode) = var fact = newNodeI(nkCall, n.info, 3) - fact.sons[0] = newSymNode(opEq) + fact.sons[0] = newSymNode(m.o.opEq) fact.sons[1] = n.sons[0] fact.sons[2] = n.sons[1] - m.add fact + m.s.add fact proc addAsgnFact*(m: var TModel, key, value: PNode) = var fact = newNodeI(nkCall, key.info, 3) - fact.sons[0] = newSymNode(opEq) + fact.sons[0] = newSymNode(m.o.opEq) fact.sons[1] = key fact.sons[2] = value - m.add fact + m.s.add fact proc sameSubexprs*(m: TModel; a, b: PNode): bool = # This should be used to check whether two *path expressions* refer to the @@ -1004,7 +1014,7 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool = # 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[0] = newSymNode(m.o.opEq) check.sons[1] = a check.sons[2] = b result = m.doesImply(check) == impYes @@ -1012,11 +1022,11 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool = proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) = let branch = n.sons[i] if branch.kind == nkOfBranch: - m.add buildOf(branch, n.sons[0]) + m.s.add buildOf(branch, n.sons[0], m.o) else: - m.add n.buildElse.neg + m.s.add n.buildElse(m.o).neg(m.o) -proc buildProperFieldCheck(access, check: PNode): PNode = +proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode = if check.sons[1].kind == nkCurly: result = copyTree(check) if access.kind == nkDotExpr: @@ -1028,10 +1038,10 @@ proc buildProperFieldCheck(access, check: PNode): PNode = else: # it is some 'not' assert check.getMagic == mNot - result = buildProperFieldCheck(access, check.sons[1]).neg + result = buildProperFieldCheck(access, check.sons[1], o).neg(o) -proc checkFieldAccess*(m: TModel, n: PNode) = +proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef) = for i in 1..n.len-1: - let check = buildProperFieldCheck(n.sons[0], n.sons[i]) + let check = buildProperFieldCheck(n.sons[0], n.sons[i], m.o) if check != nil and m.doesImply(check) != impYes: - message(n.info, warnProveField, renderTree(n.sons[0])); break + message(conf, n.info, warnProveField, renderTree(n.sons[0])); break diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 5b75596b88..fa30acb257 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -594,11 +594,11 @@ proc internalError*(conf: ConfigRef; errMsg: string) = writeContext(conf, unknownLineInfo()) rawMessage(conf, errInternal, errMsg) -template assertNotNil*(conf, e): untyped = +template assertNotNil*(conf: ConfigRef; e): untyped = if e == nil: internalError(conf, $instantiationInfo()) e -template internalAssert*(conf, e: bool) = +template internalAssert*(conf: ConfigRef, e: bool) = if not e: internalError(conf, $instantiationInfo()) proc addSourceLine*(fileIdx: FileIndex, line: string) = diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim index 4627264dc4..8790b7544f 100644 --- a/compiler/nimfix/pretty.nim +++ b/compiler/nimfix/pretty.nim @@ -13,7 +13,8 @@ import strutils, os, intsets, strtabs -import "../compiler" / [options, ast, astalgo, msgs, semdata, ropes, idents] +import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents, + configuration] import prettybase type @@ -24,8 +25,8 @@ var gStyleCheck*: StyleCheck gCheckExtern*, gOnlyMainfile*: bool -proc overwriteFiles*() = - let doStrip = options.getConfigVar("pretty.strip").normalize == "on" +proc overwriteFiles*(conf: ConfigRef) = + let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on" for i in 0 .. high(gSourceFiles): if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex): @@ -41,7 +42,7 @@ proc overwriteFiles*() = f.write(gSourceFiles[i].newline) f.close except IOError: - rawMessage(errCannotOpenFile, newFile) + rawMessage(conf, errGenerated, "cannot open file: " & newFile) proc `=~`(s: string, a: openArray[string]): bool = for x in a: @@ -110,30 +111,30 @@ proc replaceInFile(info: TLineInfo; newName: string) = system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x) gSourceFiles[info.fileIndex.int].dirty = true -proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) = +proc checkStyle(conf: ConfigRef; info: TLineInfo, s: string, k: TSymKind; sym: PSym) = let beau = beautifyName(s, k) if s != beau: if gStyleCheck == StyleCheck.Auto: sym.name = getIdent(beau) replaceInFile(info, beau) else: - message(info, hintName, beau) + message(conf, info, hintName, beau) -proc styleCheckDefImpl(info: TLineInfo; s: PSym; k: TSymKind) = +proc styleCheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) = # operators stay as they are: if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return if k in {skType, skGenericParam} and sfAnon in s.flags: return if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern: - checkStyle(info, s.name.s, k, s) + checkStyle(conf, info, s.name.s, k, s) template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) = when defined(nimfix): - if gStyleCheck != StyleCheck.None: styleCheckDefImpl(info, s, k) + if gStyleCheck != StyleCheck.None: styleCheckDefImpl(conf, info, s, k) template styleCheckDef*(info: TLineInfo; s: PSym) = - styleCheckDef(info, s, s.kind) + styleCheckDef(conf, info, s, s.kind) template styleCheckDef*(s: PSym) = - styleCheckDef(s.info, s, s.kind) + styleCheckDef(conf, s.info, s, s.kind) proc styleCheckUseImpl(info: TLineInfo; s: PSym) = if info.fileIndex.int < 0: return @@ -151,4 +152,4 @@ proc styleCheckUseImpl(info: TLineInfo; s: PSym) = template styleCheckUse*(info: TLineInfo; s: PSym) = when defined(nimfix): - if gStyleCheck != StyleCheck.None: styleCheckUseImpl(info, s) + if gStyleCheck != StyleCheck.None: styleCheckUseImpl(conf, info, s) diff --git a/compiler/options.nim b/compiler/options.nim index 4c5b6b6689..643b6f4f60 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -131,15 +131,23 @@ type symbols*: StringTableRef ## We need to use a StringTableRef here as defined ## symbols are always guaranteed to be style ## insensitive. Otherwise hell would break lose. + packageCache*: StringTableRef const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} +template newPackageCache*(): untyped = + newStringTable(when FileSystemCaseSensitive: + modeCaseInsensitive + else: + modeCaseSensitive) + proc newConfigRef*(): ConfigRef = result = ConfigRef(cppDefines: initSet[string](), headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic, hintQuitCalled, hintExecuting}, notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], - symbols: newStringTable(modeStyleInsensitive)) + symbols: newStringTable(modeStyleInsensitive), + packageCache: newPackageCache()) proc newPartialConfigRef*(): ConfigRef = ## create a new ConfigRef that is only good enough for error reporting. @@ -422,7 +430,7 @@ proc rawFindFile2(conf: ConfigRef; f: string): string = template patchModule(conf: ConfigRef) {.dirty.} = if result.len > 0 and gModuleOverrides.len > 0: - let key = getPackageName(result) & "_" & splitFile(result).name + let key = getPackageName(conf, result) & "_" & splitFile(result).name if gModuleOverrides.hasKey(key): let ov = gModuleOverrides[key] if ov.len > 0: result = ov diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim index 758411e39f..2efab58b06 100644 --- a/compiler/packagehandling.nim +++ b/compiler/packagehandling.nim @@ -15,23 +15,16 @@ iterator myParentDirs(p: string): string = if current.len == 0: break yield current -template newPackageCache(): untyped = - newStringTable(when FileSystemCaseSensitive: - modeCaseInsensitive - else: - modeCaseSensitive) +proc resetPackageCache*(conf: ConfigRef) = + conf.packageCache = newPackageCache() -var packageCache = newPackageCache() - -proc resetPackageCache*() = packageCache = newPackageCache() - -proc getPackageName*(path: string): string = +proc getPackageName*(conf: ConfigRef; path: string): string = var parents = 0 block packageSearch: for d in myParentDirs(path): - if packageCache.hasKey(d): + if conf.packageCache.hasKey(d): #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name - return packageCache[d] + return conf.packageCache[d] inc parents for file in walkFiles(d / "*.nimble"): result = file.splitFile.name @@ -43,12 +36,12 @@ proc getPackageName*(path: string): string = if result.isNil: result = "" for d in myParentDirs(path): #echo "set cache ", d, " |", result, "|", parents - packageCache[d] = result + conf.packageCache[d] = result dec parents if parents <= 0: break -proc withPackageName*(path: string): string = - let x = path.getPackageName +proc withPackageName*(conf: ConfigRef; path: string): string = + let x = getPackageName(conf, path) if x.len == 0: result = path else: diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 02c48c16d2..944aec0489 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -10,7 +10,8 @@ ## This module implements the pattern matching features for term rewriting ## macro support. -import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees +import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees, + options # we precompile the pattern here for efficiency into some internal # stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that @@ -41,8 +42,8 @@ type const MaxStackSize* = 64 ## max required stack size by the VM -proc patternError(n: PNode) = - localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) +proc patternError(n: PNode; conf: ConfigRef) = + localError(conf, n.info, "illformed AST: " & renderTree(n, {renderNoComments})) proc add(code: var TPatternCode, op: TOpcode) {.inline.} = add(code, chr(ord(op))) @@ -53,42 +54,42 @@ proc whichAlias*(p: PSym): TAliasRequest = else: result = aqNone -proc compileConstraints(p: PNode, result: var TPatternCode) = +proc compileConstraints(p: PNode, result: var TPatternCode; conf: ConfigRef) = case p.kind of nkCallKinds: if p.sons[0].kind != nkIdent: - patternError(p.sons[0]) + patternError(p.sons[0], conf) return let op = p.sons[0].ident if p.len == 3: if op.s == "|" or op.id == ord(wOr): - compileConstraints(p.sons[1], result) - compileConstraints(p.sons[2], result) + compileConstraints(p.sons[1], result, conf) + compileConstraints(p.sons[2], result, conf) result.add(ppOr) elif op.s == "&" or op.id == ord(wAnd): - compileConstraints(p.sons[1], result) - compileConstraints(p.sons[2], result) + compileConstraints(p.sons[1], result, conf) + compileConstraints(p.sons[2], result, conf) result.add(ppAnd) else: - patternError(p) + patternError(p, conf) elif p.len == 2 and (op.s == "~" or op.id == ord(wNot)): - compileConstraints(p.sons[1], result) + compileConstraints(p.sons[1], result, conf) result.add(ppNot) else: - patternError(p) + patternError(p, conf) of nkAccQuoted, nkPar: if p.len == 1: - compileConstraints(p.sons[0], result) + compileConstraints(p.sons[0], result, conf) else: - patternError(p) + patternError(p, conf) of nkIdent: let spec = p.ident.s.normalize case spec - of "atom": result.add(ppAtom) - of "lit": result.add(ppLit) - of "sym": result.add(ppSym) + of "atom": result.add(ppAtom) + of "lit": result.add(ppLit) + of "sym": result.add(ppSym) of "ident": result.add(ppIdent) - of "call": result.add(ppCall) + of "call": result.add(ppCall) of "alias": result[0] = chr(aqShouldAlias.ord) of "noalias": result[0] = chr(aqNoAlias.ord) of "lvalue": result.add(ppLValue) @@ -97,24 +98,24 @@ proc compileConstraints(p: PNode, result: var TPatternCode) = of "nosideeffect": result.add(ppNoSideEffect) else: # check all symkinds: - internalAssert int(high(TSymKind)) < 255 + internalAssert conf, int(high(TSymKind)) < 255 for i in low(TSymKind)..high(TSymKind): if cmpIgnoreStyle(($i).substr(2), spec) == 0: result.add(ppSymKind) result.add(chr(i.ord)) return # check all nodekinds: - internalAssert int(high(TNodeKind)) < 255 + internalAssert conf, int(high(TNodeKind)) < 255 for i in low(TNodeKind)..high(TNodeKind): if cmpIgnoreStyle($i, spec) == 0: result.add(ppNodeKind) result.add(chr(i.ord)) return - patternError(p) + patternError(p, conf) else: - patternError(p) + patternError(p, conf) -proc semNodeKindConstraints*(p: PNode): PNode = +proc semNodeKindConstraints*(p: PNode; conf: ConfigRef): PNode = ## does semantic checking for a node kind pattern and compiles it into an ## efficient internal format. assert p.kind == nkCurlyExpr @@ -123,11 +124,11 @@ proc semNodeKindConstraints*(p: PNode): PNode = result.strVal.add(chr(aqNone.ord)) if p.len >= 2: for i in 1.. MaxStackSize-1: - internalError(p.info, "parameter pattern too complex") + internalError(conf, p.info, "parameter pattern too complex") else: - patternError(p) + patternError(p, conf) result.strVal.add(ppEof) type diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 9fab37632f..c7fea29473 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -886,7 +886,7 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache; conf: ConfigRef): TReasonFo var hash = getHash(fileIdx) gMods[fileIdx.int32].reason = rrNone # we need to set it here to avoid cycles result = rrNone - var rodfile = toGeneratedFile(conf, filename.withPackageName, RodExt) + var rodfile = toGeneratedFile(conf, conf.withPackageName(filename), RodExt) var r = newRodReader(rodfile, hash, fileIdx.int32, cache, conf) if r == nil: result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist) diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index feab5c2540..ae6e5c99fd 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -480,7 +480,7 @@ proc writeRod(w: PRodWriter) = processStacks(w, true) var f: File if not open(f, completeGeneratedFilePath(w.config, changeFileExt( - w.filename.withPackageName, RodExt)), + withPackageName(w.config, w.filename), RodExt)), fmWrite): #echo "couldn't write rod file for: ", w.filename return diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index d2a10f714c..142fb51388 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -9,7 +9,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - wordrecg, strutils, options, guards, writetracking + wordrecg, strutils, options, guards, writetracking, configuration when defined(useDfa): import dfa @@ -52,6 +52,7 @@ type locked: seq[PNode] # locked locations gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool maxLockLevel, currLockLevel: TLockLevel + config: ConfigRef PEffects = var TEffects proc `<`(a, b: TLockLevel): bool {.borrow.} @@ -72,24 +73,23 @@ proc getLockLevel(t: PType): TLockLevel = proc lockLocations(a: PEffects; pragma: PNode) = if pragma.kind != nkExprColonExpr: - localError(pragma.info, errGenerated, "locks pragma without argument") + localError(a.config, pragma.info, "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) + localError(a.config, x.info, "invalid lock level: " & $thisLL) elif firstLL < 0.TLockLevel: firstLL = thisLL elif firstLL != thisLL: - localError(x.info, errGenerated, + localError(a.config, x.info, "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") + localError(a.config, pragma.info, "invalid nested locking") a.currLockLevel = firstLL proc guardGlobal(a: PEffects; n: PNode; guard: PSym) = @@ -102,7 +102,7 @@ proc guardGlobal(a: PEffects; n: PNode; guard: PSym) = # message(n.info, warnUnguardedAccess, renderTree(n)) #else: if not a.isTopLevel: - localError(n.info, errGenerated, "unguarded access: " & renderTree(n)) + localError(a.config, n.info, "unguarded access: " & renderTree(n)) # 'guard*' are checks which are concerned with 'guard' annotations # (var x{.guard: y.}: int) @@ -125,7 +125,7 @@ proc guardDotAccess(a: PEffects; n: PNode) = if ty == nil: break ty = ty.skipTypes(skipPtrs) if field == nil: - localError(n.info, errGenerated, "invalid guard field: " & g.name.s) + localError(a.config, n.info, "invalid guard field: " & g.name.s) return g = field #ri.sym.guard = field @@ -138,7 +138,7 @@ proc guardDotAccess(a: PEffects; n: PNode) = 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)) + localError(a.config, n.info, "unguarded access: " & renderTree(n)) else: guardGlobal(a, n, g) @@ -167,9 +167,9 @@ proc initVarViaNew(a: PEffects, n: PNode) = elif isLocalVar(a, s): makeVolatile(a, s) -proc warnAboutGcUnsafe(n: PNode) = +proc warnAboutGcUnsafe(n: PNode; conf: ConfigRef) = #assert false - message(n.info, warnGcUnsafe, renderTree(n)) + message(conf, n.info, warnGcUnsafe, renderTree(n)) proc markGcUnsafe(a: PEffects; reason: PSym) = if not a.inEnforcedGcSafe: @@ -194,42 +194,42 @@ else: a.hasSideEffect = true markGcUnsafe(a, reason) -proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) = +proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) = let u = s.gcUnsafetyReason if u != nil and not cycleCheck.containsOrIncl(u.id): let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated case u.kind of skLet, skVar: - message(s.info, msgKind, + message(conf, s.info, msgKind, ("'$#' is not GC-safe as it accesses '$#'" & " which is a global using GC'ed memory") % [s.name.s, u.name.s]) of routineKinds: # recursive call *always* produces only a warning so the full error # message is printed: - listGcUnsafety(u, true, cycleCheck) - message(s.info, msgKind, + listGcUnsafety(u, true, cycleCheck, conf) + message(conf, s.info, msgKind, "'$#' is not GC-safe as it calls '$#'" % [s.name.s, u.name.s]) of skParam, skForVar: - message(s.info, msgKind, + message(conf, s.info, msgKind, "'$#' is not GC-safe as it performs an indirect call via '$#'" % [s.name.s, u.name.s]) else: - message(u.info, msgKind, + message(conf, u.info, msgKind, "'$#' is not GC-safe as it performs an indirect call here" % s.name.s) -proc listGcUnsafety(s: PSym; onlyWarning: bool) = +proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) = var cycleCheck = initIntSet() - listGcUnsafety(s, onlyWarning, cycleCheck) + listGcUnsafety(s, onlyWarning, cycleCheck, conf) proc useVar(a: PEffects, n: PNode) = let s = n.sym if isLocalVar(a, s): if s.id notin a.init: if {tfNeedsInit, tfNotNil} * s.typ.flags != {}: - message(n.info, warnProveInit, s.name.s) + message(a.config, n.info, warnProveInit, s.name.s) else: - message(n.info, warnUninit, s.name.s) + message(a.config, n.info, warnUninit, s.name.s) # prevent superfluous warnings about the same variable: a.init.add s.id if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and @@ -257,9 +257,8 @@ 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 getEbase(g: ModuleGraph): PType = + result = g.sysTypeFromName"Exception" proc excType(n: PNode): PType = # reraise is like raising E_Base: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index c97c1186ea..4fdc743733 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -14,21 +14,21 @@ import ast, astalgo, msgs, types, magicsys, semdata, renderer, options const tfInstClearedFlags = {tfHasMeta, tfUnresolved} -proc checkPartialConstructedType(info: TLineInfo, t: PType) = +proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) = if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: - localError(info, errInvalidPragmaX, "acyclic") + localError(conf, info, "invalid pragma: acyclic") elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: - localError(info, errVarVarTypeNotAllowed) + localError(conf, info, "type 'var var' is not allowed") -proc checkConstructedType*(info: TLineInfo, typ: PType) = +proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) = var t = typ.skipTypes({tyDistinct}) if t.kind in tyTypeClasses: discard elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: - localError(info, errInvalidPragmaX, "acyclic") + localError(conf, info, "invalid pragma: acyclic") elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: - localError(info, errVarVarTypeNotAllowed) + localError(conf, info, "type 'var var' is not allowed") elif computeSize(t) == szIllegalRecursion: - localError(info, errIllegalRecursionInTypeX, typeToString(t)) + localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'") when false: if t.kind == tyObject and t.sons[0] != nil: if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: @@ -36,9 +36,8 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) = proc searchInstTypes*(key: PType): PType = let genericTyp = key.sons[0] - internalAssert genericTyp.kind == tyGenericBody and - key.sons[0] == genericTyp and - genericTyp.sym != nil + if not (genericTyp.kind == tyGenericBody and + key.sons[0] == genericTyp and genericTyp.sym != nil): return if genericTyp.sym.typeInstCache == nil: return @@ -195,19 +194,19 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode = var branch: PNode = nil # the branch to take for i in countup(0, sonsLen(n) - 1): var it = n.sons[i] - if it == nil: illFormedAst(n) + if it == nil: illFormedAst(n, cl.c.config) case it.kind of nkElifBranch: - checkSonsLen(it, 2) + checkSonsLen(it, 2, cl.c.config) var cond = prepareNode(cl, it.sons[0]) var e = cl.c.semConstExpr(cl.c, cond) if e.kind != nkIntLit: - internalError(e.info, "ReplaceTypeVarsN: when condition not a bool") + internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool") if e.intVal != 0 and branch == nil: branch = it.sons[1] of nkElse: - checkSonsLen(it, 1) + checkSonsLen(it, 1, cl.c.config) if branch == nil: branch = it.sons[0] - else: illFormedAst(n) + else: illFormedAst(n, cl.c.config) if branch != nil: result = replaceTypeVarsN(cl, branch) else: @@ -244,14 +243,14 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = result = cl.typeMap.lookup(t) if result == nil: if cl.allowMetaTypes or tfRetType in t.flags: return - localError(t.sym.info, errCannotInstantiateX, typeToString(t)) + localError(cl.c.config, t.sym.info, "cannot instantiate: " & typeToString(t)) result = errorType(cl.c) # In order to prevent endless recursions, we must remember # this bad lookup and replace it with errorType everywhere. # These code paths are only active in "nim check" cl.typeMap.put(t, result) elif result.kind == tyGenericParam and not cl.allowMetaTypes: - internalError(cl.info, "substitution with generic parameter") + internalError(cl.c.config, cl.info, "substitution with generic parameter") proc instCopyType*(cl: var TReplTypeVars, t: PType): PType = # XXX: relying on allowMetaTypes is a kludge @@ -278,7 +277,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # is difficult to handle: const eqFlags = eqTypeFlags + {tfGcSafe} var body = t.sons[0] - if body.kind != tyGenericBody: internalError(cl.info, "no generic body") + if body.kind != tyGenericBody: internalError(cl.c.config, cl.info, "no generic body") var header: PType = t # search for some instantiation here: if cl.allowMetaTypes: @@ -351,7 +350,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # handleGenericInvocation will handle the alias-to-alias-to-alias case if newbody.isGenericAlias: newbody = newbody.skipGenericAlias rawAddSon(result, newbody) - checkPartialConstructedType(cl.info, newbody) + checkPartialConstructedType(cl.c.config, cl.info, newbody) let dc = newbody.deepCopy if cl.allowMetaTypes == false: if dc != nil and sfFromGeneric notin newbody.deepCopy.flags: @@ -417,7 +416,7 @@ proc propagateFieldFlags(t: PType, n: PNode) = # The type must be fully instantiated! if n.isNil: return - internalAssert n.kind != nkRecWhen + #internalAssert n.kind != nkRecWhen case n.kind of nkSym: propagateToOwner(t, n.sym.typ) @@ -454,7 +453,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result.kind = tyUserTypeClassInst of tyGenericBody: - localError(cl.info, errCannotInstantiateX, typeToString(t)) + localError(cl.c.config, cl.info, "cannot instantiate: " & typeToString(t)) result = errorType(cl.c) #result = replaceTypeVarsT(cl, lastSon(t)) @@ -533,7 +532,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = case result.kind of tyArray: let idx = result.sons[0] - internalAssert idx.kind != tyStatic + internalAssert cl.c.config, idx.kind != tyStatic of tyObject, tyTuple: propagateFieldFlags(result, result.n) diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim index e03d6fb598..c0f7b7b20c 100644 --- a/compiler/writetracking.nim +++ b/compiler/writetracking.nim @@ -15,7 +15,7 @@ ## * Computing an aliasing relation based on the assignments. This relation ## is then used to compute the 'writes' and 'escapes' effects. -import intsets, idents, ast, astalgo, trees, renderer, msgs, types +import intsets, idents, ast, astalgo, trees, renderer, msgs, types, options const debug = false @@ -180,7 +180,7 @@ proc deps(w: var W; n: PNode) = let last = lastSon(child) if last.kind == nkEmpty: continue if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}: - internalAssert child.len-2 == last.len + if child.len-2 != last.len: return for i in 0 .. child.len-3: deps(w, child.sons[i], last.sons[i], {}) else: @@ -220,7 +220,7 @@ proc possibleAliases(w: var W; result: var seq[ptr TSym]) = # x = f(..., y, ....) for i in 0 ..< a.srcNoTc: addNoDup a.src[i] -proc markWriteOrEscape(w: var W) = +proc markWriteOrEscape(w: var W; conf: ConfigRef) = ## Both 'writes' and 'escapes' effects ultimately only care ## about *parameters*. ## However, due to aliasing, even locals that might not look as parameters @@ -249,7 +249,7 @@ proc markWriteOrEscape(w: var W) = if p.kind == skParam and p.owner == w.owner: incl(p.flags, sfWrittenTo) if w.owner.kind == skFunc and p.typ.kind != tyVar: - localError(a.info, "write access to non-var parameter: " & p.name.s) + localError(conf, a.info, "write access to non-var parameter: " & p.name.s) if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}: var destIsParam = false @@ -263,14 +263,14 @@ proc markWriteOrEscape(w: var W) = if p.kind == skParam and p.owner == w.owner: incl(p.flags, sfEscapes) -proc trackWrites*(owner: PSym; body: PNode) = +proc trackWrites*(owner: PSym; body: PNode; conf: ConfigRef) = var w: W w.owner = owner w.assignments = @[] # Phase 1: Collect and preprocess any assignments in the proc body: deps(w, body) # Phase 2: Compute the 'writes' and 'escapes' effects: - markWriteOrEscape(w) + markWriteOrEscape(w, conf) if w.returnsNew != asgnOther and not isEmptyType(owner.typ.sons[0]) and containsGarbageCollectedRef(owner.typ.sons[0]): incl(owner.typ.flags, tfReturnsNew) From 2e76a92fe191eb13b263bed354756bf61147a695 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 11 May 2018 14:18:39 +0200 Subject: [PATCH 179/214] sempass2 compiles again --- compiler/configuration.nim | 2 +- compiler/guards.nim | 4 +- compiler/sempass2.nim | 160 +++++++++++++++++++------------------ 3 files changed, 85 insertions(+), 81 deletions(-) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index 20003bb2ee..f7b9803e75 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -280,7 +280,7 @@ errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3", errWrongNumberOfArguments: "wrong number of arguments", errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", -errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar", +errXCannotBePassedToProcVar: , errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", errImplOfXNotAllowed: "implementation of '$1' is not allowed", errImplOfXexpected: , diff --git a/compiler/guards.nim b/compiler/guards.nim index 9e826b98fc..68f979a9f4 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -402,8 +402,8 @@ proc usefulFact(n: PNode; o: Operators): PNode = type TModel* = object - s: seq[PNode] # the "knowledge base" - o: Operators + s*: seq[PNode] # the "knowledge base" + o*: Operators proc addFact*(m: var TModel, nn: PNode) = let n = usefulFact(nn, m.o) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 142fb51388..015e81b1fd 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -9,7 +9,8 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - wordrecg, strutils, options, guards, writetracking, configuration + wordrecg, strutils, options, guards, writetracking, configuration, + modulegraphs when defined(useDfa): import dfa @@ -53,6 +54,7 @@ type gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool maxLockLevel, currLockLevel: TLockLevel config: ConfigRef + graph: ModuleGraph PEffects = var TEffects proc `<`(a, b: TLockLevel): bool {.borrow.} @@ -257,32 +259,29 @@ 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(g: ModuleGraph): PType = - result = g.sysTypeFromName"Exception" +proc getEbase(g: ModuleGraph; info: TLineInfo): PType = + result = g.sysTypeFromName(info, "Exception") -proc excType(n: PNode): PType = +proc excType(g: ModuleGraph; n: PNode): PType = # reraise is like raising E_Base: - let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ + let t = if n.kind == nkEmpty or n.typ.isNil: getEbase(g, n.info) else: n.typ result = skipTypes(t, skipPtrs) -proc createRaise(n: PNode): PNode = +proc createRaise(g: ModuleGraph; n: PNode): PNode = result = newNode(nkType) - result.typ = getEbase() + result.typ = getEbase(g, n.info) if not n.isNil: result.info = n.info -proc createTag(n: PNode): PNode = +proc createTag(g: ModuleGraph; n: PNode): PNode = result = newNode(nkType) - if getCompilerProc("RootEffect") != nil: - result.typ = sysTypeFromName"RootEffect" - else: - result.typ = sysTypeFromName"TEffect" + result.typ = g.sysTypeFromName(n.info, "RootEffect") if not n.isNil: result.info = n.info proc addEffect(a: PEffects, e: PNode, useLineInfo=true) = assert e.kind != nkRaiseStmt var aa = a.exc for i in a.bottom ..< aa.len: - if sameType(aa[i].excType, e.excType): + if sameType(a.graph.excType(aa[i]), a.graph.excType(e)): if not useLineInfo or gCmd == cmdDoc: return elif aa[i].info == e.info: return throws(a.exc, e) @@ -297,19 +296,19 @@ proc addTag(a: PEffects, e: PNode, useLineInfo=true) = proc mergeEffects(a: PEffects, b, comesFrom: PNode) = if b.isNil: - addEffect(a, createRaise(comesFrom)) + addEffect(a, createRaise(a.graph, comesFrom)) else: for effect in items(b): addEffect(a, effect, useLineInfo=comesFrom != nil) proc mergeTags(a: PEffects, b, comesFrom: PNode) = if b.isNil: - addTag(a, createTag(comesFrom)) + addTag(a, createTag(a.graph, comesFrom)) else: for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil) 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.exc): message(a.config, e.info, hintUser, typeToString(e.typ)) + for e in items(a.tags): message(a.config, e.info, hintUser, typeToString(e.typ)) #if a.maxLockLevel != 0: # message(e.info, hintUser, "lockLevel: " & a.maxLockLevel) @@ -319,7 +318,7 @@ proc catches(tracked: PEffects, e: PType) = var i = tracked.bottom while i < L: # r supertype of e? - if safeInheritanceDiff(tracked.exc[i].excType, e) <= 0: + if safeInheritanceDiff(tracked.graph.excType(tracked.exc[i]), e) <= 0: tracked.exc.sons[i] = tracked.exc.sons[L-1] dec L else: @@ -488,7 +487,7 @@ 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, + localError tracked.config, n.info, errGenerated, "expected lock level < " & $tracked.currLockLevel & " but got lock level " & $lockLevel tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel) @@ -502,22 +501,22 @@ 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: warnAboutGcUnsafe(n) + if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, s) if tfNoSideEffect notin s.typ.flags: markSideEffect(tracked, s) mergeLockLevels(tracked, n, s.getLockLevel) -proc procVarcheck(n: PNode) = +proc procVarcheck(n: PNode; conf: ConfigRef) = if n.kind in nkSymChoices: - for x in n: procVarCheck(x) + for x in n: procVarCheck(x, conf) elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds: - localError(n.info, errXCannotBePassedToProcVar, n.sym.name.s) + localError(conf, n.info, "'$1' cannot be passed to a procvar" % n.sym.name.s) proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = let n = n.skipConv if paramType.isNil or paramType.kind != tyTypeDesc: - procVarcheck skipConvAndClosure(n) + procVarcheck skipConvAndClosure(n), tracked.config #elif n.kind in nkSymChoices: # echo "came here" let paramType = paramType.skipTypesOrNil(abstractInst) @@ -533,15 +532,16 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = return case impliesNotNil(tracked.guards, n) of impUnknown: - message(n.info, errGenerated, + message(tracked.config, n.info, errGenerated, "cannot prove '$1' is not nil" % n.renderTree) of impNo: - message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree) + message(tracked.config, 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)) + addEffect(tracked, createRaise(tracked.graph, n)) + addTag(tracked, createTag(tracked.graph, n)) let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel else: op.lockLevel #if lockLevel == UnknownLockLevel: @@ -556,7 +556,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = let a = skipConvAndClosure(n) let op = a.typ if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit: - internalAssert op.n.sons[0].kind == nkEffectList + internalAssert tracked.config, op.n.sons[0].kind == nkEffectList var effectList = op.n.sons[0] let s = n.skipConv if s.kind == nkSym and s.sym.kind in routineKinds: @@ -571,7 +571,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = assumeTheWorst(tracked, n, op) # assume GcUnsafe unless in its type; 'forward' does not matter: if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner): - if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) + if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, a) elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner): markSideEffect(tracked, a) @@ -579,7 +579,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) if notGcSafe(op): - if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) + if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, a) elif tfNoSideEffect notin op.flags: markSideEffect(tracked, a) @@ -591,7 +591,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = # XXX figure out why this can be a non tyProc here. See httpclient.nim for an # example that triggers it. if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe: - localError(n.info, $n & " is not GC safe") + localError(tracked.config, n.info, $n & " is not GC safe") notNilCheck(tracked, n, paramType) proc breaksBlock(n: PNode): bool = @@ -607,18 +607,18 @@ proc breaksBlock(n: PNode): bool = proc trackCase(tracked: PEffects, n: PNode) = track(tracked, n.sons[0]) let oldState = tracked.init.len - let oldFacts = tracked.guards.len + let oldFacts = tracked.guards.s.len let stringCase = skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString} let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and - warnProveField in gNotes + warnProveField in tracked.config.notes var inter: TIntersection = @[] var toCover = 0 for i in 1..= toCover: tracked.init.add id # else we can't merge - setLen(tracked.guards, oldFacts) + setLen(tracked.guards.s, oldFacts) proc trackIf(tracked: PEffects, n: PNode) = track(tracked, n.sons[0].sons[0]) - let oldFacts = tracked.guards.len + let oldFacts = tracked.guards.s.len addFact(tracked.guards, n.sons[0].sons[0]) let oldState = tracked.init.len @@ -648,7 +648,7 @@ proc trackIf(tracked: PEffects, n: PNode) = for i in 1.. 1: @@ -664,7 +664,7 @@ proc trackIf(tracked: PEffects, n: PNode) = for id, count in items(inter): if count >= toCover: tracked.init.add id # else we can't merge as it is not exhaustive - setLen(tracked.guards, oldFacts) + setLen(tracked.guards.s, oldFacts) proc trackBlock(tracked: PEffects, n: PNode) = if n.kind in {nkStmtList, nkStmtListExpr}: @@ -692,7 +692,7 @@ proc paramType(op: PType, i: int): PType = proc cstringCheck(tracked: PEffects; n: PNode) = if n.sons[0].typ.kind == tyCString and (let a = skipConv(n[1]); a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}): - message(n.info, warnUnsafeCode, renderTree(n)) + message(tracked.config, n.info, warnUnsafeCode, renderTree(n)) proc track(tracked: PEffects, n: PNode) = case n.kind @@ -734,7 +734,7 @@ proc track(tracked: PEffects, n: PNode) = if notGcSafe(op) and not importedFromC(a): # and it's not a recursive call: if not (a.kind == nkSym and a.sym == tracked.owner): - if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) + if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config) markGcUnsafe(tracked, a) if tfNoSideEffect notin op.flags and not importedFromC(a): # and it's not a recursive call: @@ -752,7 +752,7 @@ proc track(tracked: PEffects, n: PNode) = # var s: seq[notnil]; newSeq(s, 0) is a special case! discard else: - message(arg.info, warnProveInit, $arg) + message(tracked.config, arg.info, warnProveInit, $arg) for i in 0 ..< safeLen(n): track(tracked, n.sons[i]) of nkDotExpr: @@ -760,7 +760,8 @@ proc track(tracked: PEffects, n: PNode) = 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) + if warnProveField in tracked.config.notes: + checkFieldAccess(tracked.guards, n, tracked.config) of nkTryStmt: trackTryStmt(tracked, n) of nkPragma: trackPragmaStmt(tracked, n) of nkAsgn, nkFastAsgn: @@ -797,11 +798,11 @@ proc track(tracked: PEffects, n: PNode) = else: # loop may never execute: let oldState = tracked.init.len - let oldFacts = tracked.guards.len + let oldFacts = tracked.guards.s.len addFact(tracked.guards, n.sons[0]) track(tracked, n.sons[1]) setLen(tracked.init, oldState) - setLen(tracked.guards, oldFacts) + setLen(tracked.guards.s, oldFacts) of nkForStmt, nkParForStmt: # we are very conservative here and assume the loop is never executed: let oldState = tracked.init.len @@ -810,13 +811,13 @@ proc track(tracked: PEffects, n: PNode) = setLen(tracked.init, oldState) of nkObjConstr: when false: track(tracked, n.sons[0]) - let oldFacts = tracked.guards.len + let oldFacts = tracked.guards.s.len for i in 1 ..< len(n): let x = n.sons[i] track(tracked, x) if x.sons[0].kind == nkSym and sfDiscriminant in x.sons[0].sym.flags: addDiscriminantFact(tracked.guards, x) - setLen(tracked.guards, oldFacts) + setLen(tracked.guards.s, oldFacts) of nkPragmaBlock: let pragmaList = n.sons[0] let oldLocked = tracked.locked.len @@ -843,31 +844,31 @@ proc track(tracked: PEffects, n: PNode) = else: for i in 0 ..< safeLen(n): track(tracked, n.sons[i]) -proc subtypeRelation(spec, real: PNode): bool = - result = safeInheritanceDiff(real.excType, spec.typ) <= 0 +proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool = + result = safeInheritanceDiff(g.excType(real), spec.typ) <= 0 -proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool; - effectPredicate: proc (a, b: PNode): bool {.nimcall.}) = +proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool; + effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.}) = # check that any real exception is listed in 'spec'; mark those as used; # report any unused exception var used = initIntSet() for r in items(real): block search: for s in 0 ..< spec.len: - if effectPredicate(spec[s], r): + if effectPredicate(g, spec[s], r): used.incl(s) break search # XXX call graph analysis would be nice here! pushInfoContext(spec.info) - localError(r.info, errGenerated, msg & typeToString(r.typ)) + localError(g.config, r.info, errGenerated, msg & typeToString(r.typ)) popInfoContext() # hint about unnecessarily listed exception types: if hints: for s in 0 ..< spec.len: if not used.contains(s): - message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s])) + message(g.config, spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s])) -proc checkMethodEffects*(disp, branch: PSym) = +proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) = ## checks for consistent effects for multi methods. let actual = branch.typ.n.sons[0] if actual.len != effectListLen: return @@ -875,42 +876,42 @@ proc checkMethodEffects*(disp, branch: PSym) = let p = disp.ast.sons[pragmasPos] let raisesSpec = effectSpec(p, wRaises) if not isNil(raisesSpec): - checkRaisesSpec(raisesSpec, actual.sons[exceptionEffects], + checkRaisesSpec(g, raisesSpec, actual.sons[exceptionEffects], "can raise an unlisted exception: ", hints=off, subtypeRelation) let tagsSpec = effectSpec(p, wTags) if not isNil(tagsSpec): - checkRaisesSpec(tagsSpec, actual.sons[tagEffects], + checkRaisesSpec(g, tagsSpec, actual.sons[tagEffects], "can have an unlisted effect: ", hints=off, subtypeRelation) if sfThread in disp.flags and notGcSafe(branch.typ): - localError(branch.info, "base method is GC-safe, but '$1' is not" % + localError(g.config, 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, + message(g.config, 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, + localError(g.config, branch.info, "base method has lock level $1, but dispatcher has $2" % [$branch.typ.lockLevel, $disp.typ.lockLevel]) -proc setEffectsForProcType*(t: PType, n: PNode) = +proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) = var effects = t.n.sons[0] - internalAssert t.kind == tyProc and effects.kind == nkEffectList + if t.kind != tyProc or effects.kind != nkEffectList: return let raisesSpec = effectSpec(n, wRaises) tagsSpec = effectSpec(n, wTags) if not isNil(raisesSpec) or not isNil(tagsSpec): - internalAssert effects.len == 0 + internalAssert g.config, effects.len == 0 newSeq(effects.sons, effectListLen) if not isNil(raisesSpec): effects.sons[exceptionEffects] = raisesSpec if not isNil(tagsSpec): effects.sons[tagEffects] = tagsSpec -proc initEffects(effects: PNode; s: PSym; t: var TEffects) = +proc initEffects(g: ModuleGraph; 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) @@ -921,36 +922,39 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) = t.tags = effects.sons[tagEffects] t.owner = s t.init = @[] - t.guards = @[] + t.guards.s = @[] + t.guards.o = initOperators(g) t.locked = @[] + t.graph = g + t.config = g.config -proc trackProc*(s: PSym, body: PNode) = +proc trackProc*(g: ModuleGraph; s: PSym, body: PNode) = var effects = s.typ.n.sons[0] - internalAssert effects.kind == nkEffectList + if effects.kind != nkEffectList: return # effects already computed? if sfForward in s.flags: return if effects.len == effectListLen: return var t: TEffects - initEffects(effects, s, t) + initEffects(g, effects, s, t) track(t, body) if not isEmptyType(s.typ.sons[0]) and {tfNeedsInit, tfNotNil} * s.typ.sons[0].flags != {} and s.kind in {skProc, skFunc, skConverter, skMethod}: var res = s.ast.sons[resultPos].sym # get result symbol if res.id notin t.init: - message(body.info, warnProveInit, "result") + message(g.config, body.info, warnProveInit, "result") let p = s.ast.sons[pragmasPos] let raisesSpec = effectSpec(p, wRaises) if not isNil(raisesSpec): - checkRaisesSpec(raisesSpec, t.exc, "can raise an unlisted exception: ", + checkRaisesSpec(g, raisesSpec, t.exc, "can raise an unlisted exception: ", hints=on, subtypeRelation) # after the check, use the formal spec: effects.sons[exceptionEffects] = raisesSpec let tagsSpec = effectSpec(p, wTags) if not isNil(tagsSpec): - checkRaisesSpec(tagsSpec, t.tags, "can have an unlisted effect: ", + checkRaisesSpec(g, tagsSpec, t.tags, "can have an unlisted effect: ", hints=off, subtypeRelation) # after the check, use the formal spec: effects.sons[tagEffects] = tagsSpec @@ -958,15 +962,15 @@ proc trackProc*(s: PSym, body: PNode) = if sfThread in s.flags and t.gcUnsafe: if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions: #localError(s.info, "'$1' is not GC-safe" % s.name.s) - listGcUnsafety(s, onlyWarning=false) + listGcUnsafety(s, onlyWarning=false, g.config) else: - listGcUnsafety(s, onlyWarning=true) + listGcUnsafety(s, onlyWarning=true, g.config) #localError(s.info, warnGcUnsafe2, s.name.s) if sfNoSideEffect in s.flags and t.hasSideEffect: when false: - listGcUnsafety(s, onlyWarning=false) + listGcUnsafety(s, onlyWarning=false, g.config) else: - localError(s.info, errXhasSideEffects, s.name.s) + localError(g.config, s.info, "'$1' has side effects" % s.name.s) if not t.gcUnsafe: s.typ.flags.incl tfGcSafe if not t.hasSideEffect and sfSideEffect notin s.flags: @@ -975,7 +979,7 @@ proc trackProc*(s: PSym, body: PNode) = s.typ.lockLevel = t.maxLockLevel elif t.maxLockLevel > s.typ.lockLevel: #localError(s.info, - message(s.info, warnLockLevel, + message(g.config, s.info, warnLockLevel, "declared lock level is $1, but real lock level is $2" % [$s.typ.lockLevel, $t.maxLockLevel]) when defined(useDfa): @@ -983,12 +987,12 @@ proc trackProc*(s: PSym, body: PNode) = dataflowAnalysis(s, body) when false: trackWrites(s, body) -proc trackTopLevelStmt*(module: PSym; n: PNode) = +proc trackTopLevelStmt*(g: ModuleGraph; module: PSym; n: PNode) = if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef, nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}: return var effects = newNode(nkEffectList, n.info) var t: TEffects - initEffects(effects, module, t) + initEffects(g, effects, module, t) t.isToplevel = true track(t, n) From a8a544a8f716f98a8f20cd3baea5291d0de72a16 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 11 May 2018 15:01:28 +0200 Subject: [PATCH 180/214] avoid more global variables --- compiler/commands.nim | 12 ++++----- compiler/configuration.nim | 13 ++++++++- compiler/docgen.nim | 54 ++++++++++++++++++++------------------ compiler/lexer.nim | 2 +- compiler/msgs.nim | 12 ++++----- compiler/nimconf.nim | 4 +-- compiler/nversion.nim | 3 +++ compiler/options.nim | 33 +++++++++++------------ compiler/typesrenderer.nim | 7 ++--- 9 files changed, 79 insertions(+), 61 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 46ade667e5..6ca212ddbc 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -490,10 +490,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "oldnewlines": case arg.normalize of "on": - options.gOldNewlines = true + conf.oldNewlines = true defineSymbol(conf.symbols, "nimOldNewlines") of "off": - options.gOldNewlines = false + conf.oldNewlines = false undefSymbol(conf.symbols, "nimOldNewlines") else: localError(conf, info, errOnOrOffExpectedButXFound % arg) @@ -671,19 +671,19 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; trackDirty(conf, arg, info) of "suggest": expectNoArg(conf, switch, arg, pass, info) - gIdeCmd = ideSug + conf.ideCmd = ideSug of "def": expectNoArg(conf, switch, arg, pass, info) - gIdeCmd = ideDef + conf.ideCmd = ideDef of "eval": expectArg(conf, switch, arg, pass, info) gEvalExpr = arg of "context": expectNoArg(conf, switch, arg, pass, info) - gIdeCmd = ideCon + conf.ideCmd = ideCon of "usages": expectNoArg(conf, switch, arg, pass, info) - gIdeCmd = ideUse + conf.ideCmd = ideUse of "stdout": expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optStdout) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index f7b9803e75..5164fd6df9 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -18,7 +18,13 @@ const type TMsgKind* = enum - errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated, + errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, + errXExpected, + errGridTableNotImplemented, + errGeneralParseError, + errNewSectionExpected, + errInvalidDirectiveX, + errGenerated, errUser, warnCannotOpenFile, warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, @@ -47,6 +53,11 @@ const errInternal: "internal error: $1", errIllFormedAstX: "illformed AST: $1", errCannotOpenFile: "cannot open '$1'", + errXExpected: "'$1' expected", + errGridTableNotImplemented: "grid table is not implemented", + errGeneralParseError: "general parse error", + errNewSectionExpected: "new section expected", + errInvalidDirectiveX: "invalid directive: '$1'", errGenerated: "$1", errUser: "$1", warnCannotOpenFile: "cannot open '$1'", diff --git a/compiler/docgen.nim b/compiler/docgen.nim index e1a70a23e9..a21c8073f0 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -16,7 +16,7 @@ import wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast, packages/docutils/rst, packages/docutils/rstgen, times, packages/docutils/highlite, sempass2, json, xmltree, cgi, - typesrenderer, astalgo, modulepaths + typesrenderer, astalgo, modulepaths, configuration type TSections = array[TSymKind, Rope] @@ -53,36 +53,40 @@ proc attachToType(d: PDoc; p: PSym): PSym = if params.len > 0: check(0) for i in 2..= gcRefc -template preciseStack*(): bool = gPreciseStack +proc importantComments*(conf: ConfigRef): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} +proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = gSelectedGC >= gcRefc +template preciseStack*(conf: ConfigRef): bool = gPreciseStack -template compilationCachePresent*: untyped = +template compilationCachePresent*(conf: ConfigRef): untyped = gSymbolFiles in {enabledSf, writeOnlySf} # {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {} -template optPreserveOrigSource*: untyped = +template optPreserveOrigSource*(conf: ConfigRef): untyped = optEmbedOrigSrc in gGlobalOptions const @@ -264,7 +264,6 @@ const # additional configuration variables: var - gConfigVars* = newStringTable(modeStyleInsensitive) gDllOverrides = newStringTable(modeCaseInsensitive) gModuleOverrides* = newStringTable(modeStyleInsensitive) gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc. @@ -283,10 +282,10 @@ var const oKeepVariableNames* = true -template compilingLib*: bool = +template compilingLib*(conf: ConfigRef): bool = gGlobalOptions * {optGenGuiApp, optGenDynLib} != {} -proc mainCommandArg*: string = +proc mainCommandArg*(conf: ConfigRef): string = ## This is intended for commands like check or parse ## which will work on the main project file unless ## explicitly given a specific file argument @@ -296,13 +295,13 @@ proc mainCommandArg*: string = result = gProjectName proc existsConfigVar*(conf: ConfigRef; key: string): bool = - result = hasKey(gConfigVars, key) + result = hasKey(conf.configVars, key) proc getConfigVar*(conf: ConfigRef; key: string): string = - result = gConfigVars.getOrDefault key + result = conf.configVars.getOrDefault key proc setConfigVar*(conf: ConfigRef; key, val: string) = - gConfigVars[key] = val + conf.configVars[key] = val proc getOutFile*(conf: ConfigRef; filename, ext: string): string = if options.outFile != "": result = options.outFile diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index 4a9b8d1a9a..4d75d5d058 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -17,7 +17,6 @@ proc renderPlainSymbolName*(n: PNode): string = ## Use this on documentation name nodes to extract the *raw* symbol name, ## without decorations, parameters, or anything. That can be used as the base ## for the HTML hyperlinks. - result = "" case n.kind of nkPostfix, nkAccQuoted: result = renderPlainSymbolName(n[n.len-1]) @@ -28,7 +27,8 @@ proc renderPlainSymbolName*(n: PNode): string = of nkPragmaExpr: result = renderPlainSymbolName(n[0]) else: - internalError(n.info, "renderPlainSymbolName() with " & $n.kind) + result = "" + #internalError(n.info, "renderPlainSymbolName() with " & $n.kind) assert(not result.isNil) proc renderType(n: PNode): string = @@ -105,7 +105,8 @@ proc renderParamTypes(found: var seq[string], n: PNode) = for i in 0 ..< typePos: found.add(typeStr) else: - internalError(n.info, "renderParamTypes(found,n) with " & $n.kind) + found.add($n) + #internalError(n.info, "renderParamTypes(found,n) with " & $n.kind) proc renderParamTypes*(n: PNode, sep = defaultParamSeparator): string = ## Returns the types contained in `n` joined by `sep`. From 3c4ceea4272a8e9d817e16e71581f8fa15460a34 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 11 May 2018 15:28:26 +0200 Subject: [PATCH 181/214] move more global variables into ConfigRef --- compiler/commands.nim | 32 +++++----- compiler/extccomp.nim | 26 ++++---- compiler/modulepaths.nim | 2 +- compiler/msgs.nim | 2 +- compiler/nimblecmd.nim | 8 +-- compiler/nimconf.nim | 10 ++-- compiler/nimfix/pretty.nim | 2 +- compiler/options.nim | 120 ++++++++++++++++++++----------------- compiler/passes.nim | 4 +- compiler/rodread.nim | 2 +- compiler/rodwrite.nim | 2 +- 11 files changed, 109 insertions(+), 101 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 6ca212ddbc..ba6bbab7d9 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -287,7 +287,7 @@ proc processPath(conf: ConfigRef; path: string, info: TLineInfo, elif notRelativeToProj: getCurrentDir() / path else: - options.gProjectPath / path + conf.projectPath / path try: result = pathSubs(conf, p, info.toFullPath().splitFile().dir) except ValueError: @@ -366,22 +366,22 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectArg(conf, switch, arg, pass, info) let path = processPath(conf, arg, info) - options.searchPaths.keepItIf(cmpPaths(it, path) != 0) - options.lazyPaths.keepItIf(cmpPaths(it, path) != 0) + conf.searchPaths.keepItIf(cmpPaths(it, path) != 0) + conf.lazyPaths.keepItIf(cmpPaths(it, path) != 0) if (len(path) > 0) and (path[len(path) - 1] == DirSep): let strippedPath = path[0 .. (len(path) - 2)] - options.searchPaths.keepItIf(cmpPaths(it, strippedPath) != 0) - options.lazyPaths.keepItIf(cmpPaths(it, strippedPath) != 0) + conf.searchPaths.keepItIf(cmpPaths(it, strippedPath) != 0) + conf.lazyPaths.keepItIf(cmpPaths(it, strippedPath) != 0) of "nimcache": expectArg(conf, switch, arg, pass, info) - options.nimcacheDir = processPath(conf, arg, info, true) + conf.nimcacheDir = processPath(conf, arg, info, true) of "out", "o": expectArg(conf, switch, arg, pass, info) - options.outFile = arg + conf.outFile = arg of "docseesrcurl": expectArg(conf, switch, arg, pass, info) - options.docSeeSrcUrl = arg + conf.docSeeSrcUrl = arg of "mainmodule", "m": discard "allow for backwards compatibility, but don't do anything" of "define", "d": @@ -579,10 +579,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info) of "import": expectArg(conf, switch, arg, pass, info) - if pass in {passCmd2, passPP}: implicitImports.add arg + if pass in {passCmd2, passPP}: conf.implicitImports.add arg of "include": expectArg(conf, switch, arg, pass, info) - if pass in {passCmd2, passPP}: implicitIncludes.add arg + if pass in {passCmd2, passPP}: conf.implicitIncludes.add arg of "listcmd": expectNoArg(conf, switch, arg, pass, info) incl(gGlobalOptions, optListCmd) @@ -655,7 +655,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info) of "lib": expectArg(conf, switch, arg, pass, info) - libpath = processPath(conf, arg, info, notRelativeToProj=true) + conf.libpath = processPath(conf, arg, info, notRelativeToProj=true) of "putenv": expectArg(conf, switch, arg, pass, info) splitSwitch(conf, arg, key, val, pass, info) @@ -751,17 +751,17 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser; if argsCount == 0: # nim filename.nims is the same as "nim e filename.nims": if p.key.endswith(".nims"): - options.command = "e" - options.gProjectName = unixToNativePath(p.key) + config.command = "e" + config.projectName = unixToNativePath(p.key) config.arguments = cmdLineRest(p) result = true elif pass != passCmd2: - options.command = p.key + config.command = p.key else: - if pass == passCmd1: options.commandArgs.add p.key + if pass == passCmd1: config.commandArgs.add p.key if argsCount == 1: # support UNIX style filenames everywhere for portable build scripts: - options.gProjectName = unixToNativePath(p.key) + config.projectName = unixToNativePath(p.key) config.arguments = cmdLineRest(p) result = true inc argsCount diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index bab612835f..bded6b3f15 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -474,7 +474,7 @@ proc generateScript(conf: ConfigRef; projectFile: string, script: Rope) = let (dir, name, ext) = splitFile(projectFile) writeRope(script, getNimcacheDir(conf) / addFileExt("compile_" & name, platform.OS[targetOS].scriptExt)) - copyFile(libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h") + copyFile(conf.libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h") proc getOptSpeed(conf: ConfigRef; c: TSystemCC): string = result = getConfigVar(conf, c, ".options.speed") @@ -563,7 +563,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string = var includeCmd, compilePattern: string if not noAbsolutePaths(conf): # compute include paths: - includeCmd = CC[c].includeCmd & quoteShell(libpath) + includeCmd = CC[c].includeCmd & quoteShell(conf.libpath) for includeDir in items(cIncludes): includeCmd.add(join([CC[c].includeCmd, includeDir.quoteShell])) @@ -592,14 +592,14 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string = result = quoteShell(compilePattern % [ "file", cf, "objfile", objfile, "options", options, "include", includeCmd, "nim", getPrefixDir(conf), - "nim", getPrefixDir(conf), "lib", libpath]) + "nim", getPrefixDir(conf), "lib", conf.libpath]) add(result, ' ') addf(result, CC[c].compileTmpl, [ "file", cf, "objfile", objfile, "options", options, "include", includeCmd, "nim", quoteShell(getPrefixDir(conf)), "nim", quoteShell(getPrefixDir(conf)), - "lib", quoteShell(libpath)]) + "lib", quoteShell(conf.libpath)]) proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = result = secureHash( @@ -655,12 +655,12 @@ proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = if optGenStaticLib in gGlobalOptions: var libname: string - if options.outFile.len > 0: - libname = options.outFile.expandTilde + if conf.outFile.len > 0: + libname = conf.outFile.expandTilde if not libname.isAbsolute(): libname = getCurrentDir() / libname else: - libname = (libNameTmpl() % splitFile(gProjectName).name) + libname = (libNameTmpl() % splitFile(conf.projectName).name) result = CC[cCompiler].buildLib % ["libfile", libname, "objfiles", objfiles] else: @@ -679,8 +679,8 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = else: exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt builddll = "" - if options.outFile.len > 0: - exefile = options.outFile.expandTilde + if conf.outFile.len > 0: + exefile = conf.outFile.expandTilde if not exefile.isAbsolute(): exefile = getCurrentDir() / exefile if not noAbsolutePaths(conf): @@ -697,13 +697,13 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = linkTmpl = CC[cCompiler].linkTmpl result = quoteShell(result % ["builddll", builddll, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, - "exefile", exefile, "nim", getPrefixDir(conf), "lib", libpath]) + "exefile", exefile, "nim", getPrefixDir(conf), "lib", conf.libpath]) result.add ' ' addf(result, linkTmpl, ["builddll", builddll, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "exefile", exefile, "nim", quoteShell(getPrefixDir(conf)), - "lib", quoteShell(libpath)]) + "lib", quoteShell(conf.libpath)]) template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped): typed = try: @@ -903,7 +903,7 @@ proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) = getConfigVar(conf, cCompiler, ".options.linker"))) add(code, "\n[Environment]\nlibpath=") - add(code, strutils.escape(libpath)) + add(code, strutils.escape(conf.libpath)) addf(code, "\n[Symbols]$n$1", [symbolMapping]) - writeRope(code, joinPath(gProjectPath, "mapping.txt")) + writeRope(code, joinPath(conf.projectPath, "mapping.txt")) diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index c2e349c4ee..daa55c2ba5 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -152,7 +152,7 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string = let x = addFileExt(a, "nim") if fileExists(x): return x for candidate in stdlibDirs: - attempt(options.libpath / candidate / modname) + attempt(conf.libpath / candidate / modname) # hacky way to implement 'x / y /../ z': result = getModuleName(conf, n1) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 1efc3c944b..d8e5a5c279 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -400,7 +400,7 @@ proc quit(conf: ConfigRef; msg: TMsgKind) = else: styledMsgWriteln(fgRed, "No stack traceback available\n" & "To create a stacktrace, rerun compilation with ./koch temp " & - options.command & " ") + conf.command & " ") quit 1 proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) = diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index da83e94999..8305b01f53 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -13,8 +13,8 @@ import parseutils, strutils, strtabs, os, options, msgs, sequtils, configuration proc addPath*(conf: ConfigRef; path: string, info: TLineInfo) = - if not options.searchPaths.contains(path): - options.searchPaths.insert(path, 0) + if not conf.searchPaths.contains(path): + conf.searchPaths.insert(path, 0) type Version* = distinct string @@ -112,9 +112,9 @@ proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) = if not path.isAbsolute(): path = p / path - if not contains(options.searchPaths, path): + if not contains(conf.searchPaths, path): message(conf, info, hintPath, path) - options.lazyPaths.insert(path, 0) + conf.lazyPaths.insert(path, 0) proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) = var packages = newStringTable(modeStyleInsensitive) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index b333252a1c..6a26f8dc74 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -239,7 +239,7 @@ proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) = if optSkipUserConfigFile notin gGlobalOptions: readConfigFile(getUserConfigPath(cfg), cache, config) - let pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir() + let pd = if config.projectPath.len > 0: config.projectPath else: getCurrentDir() if optSkipParentConfigFiles notin gGlobalOptions: for dir in parentDirs(pd, fromRoot=true, inclusive=false): readConfigFile(dir / cfg, cache, config) @@ -247,13 +247,13 @@ proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) = if optSkipProjConfigFile notin gGlobalOptions: readConfigFile(pd / cfg, cache, config) - if gProjectName.len != 0: + if config.projectName.len != 0: # new project wide config file: - var projectConfig = changeFileExt(gProjectFull, "nimcfg") + var projectConfig = changeFileExt(config.projectFull, "nimcfg") if not fileExists(projectConfig): - projectConfig = changeFileExt(gProjectFull, "nim.cfg") + projectConfig = changeFileExt(config.projectFull, "nim.cfg") readConfigFile(projectConfig, cache, config) -proc loadConfigs*(cfg: string; config: ConfigRef = nil) = +proc loadConfigs*(cfg: string; config: ConfigRef) = # for backwards compatibility only. loadConfigs(cfg, newIdentCache(), config) diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim index 8790b7544f..c68c3ccf16 100644 --- a/compiler/nimfix/pretty.nim +++ b/compiler/nimfix/pretty.nim @@ -29,7 +29,7 @@ proc overwriteFiles*(conf: ConfigRef) = let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on" for i in 0 .. high(gSourceFiles): if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and - (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex): + (not gOnlyMainfile or gSourceFiles[i].fileIdx == conf.projectMainIdx.FileIndex): let newFile = if gOverWrite: gSourceFiles[i].fullpath else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim") try: diff --git a/compiler/options.nim b/compiler/options.nim index 8aa438917d..9d265d5031 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -135,6 +135,22 @@ type ## symbols are always guaranteed to be style ## insensitive. Otherwise hell would break lose. packageCache*: StringTableRef + searchPaths*: seq[string] + lazyPaths*: seq[string] + outFile*, prefixDir*, libpath*, nimcacheDir*: string + dllOverrides, moduleOverrides*: StringTableRef + projectName*: string # holds a name like 'nim' + projectPath*: string # holds a path like /home/alice/projects/nim/compiler/ + projectFull*: string # projectPath/projectName + projectIsStdin*: bool # whether we're compiling from stdin + projectMainIdx*: int32 # the canonical path id of the main module + command*: string # the main command (e.g. cc, check, scan, etc) + commandArgs*: seq[string] # any arguments after the main command + keepComments*: bool # whether the parser needs to keep comments + implicitImports*: seq[string] # modules that are to be implicitly imported + implicitIncludes*: seq[string] # modules that are to be implicitly included + docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \ + # The string uses the formatting variables `path` and `line`. const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} @@ -151,7 +167,24 @@ proc newConfigRef*(): ConfigRef = notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], configVars: newStringTable(modeStyleInsensitive), symbols: newStringTable(modeStyleInsensitive), - packageCache: newPackageCache()) + packageCache: newPackageCache(), + searchPaths: @[], + lazyPaths: @[], + outFile: "", prefixDir: "", libpath: "", nimcacheDir: "", + dllOverrides: newStringTable(modeCaseInsensitive), + moduleOverrides: newStringTable(modeStyleInsensitive), + projectName: "", # holds a name like 'nim' + projectPath: "", # holds a path like /home/alice/projects/nim/compiler/ + projectFull: "", # projectPath/projectName + projectIsStdin: false, # whether we're compiling from stdin + projectMainIdx: 0'i32, # the canonical path id of the main module + command: "", # the main command (e.g. cc, check, scan, etc) + commandArgs: @[], # any arguments after the main command + keepComments: true, # whether the parser needs to keep comments + implicitImports: @[], # modules that are to be implicitly imported + implicitIncludes: @[], # modules that are to be implicitly included + docSeeSrcUrl: "" + ) proc newPartialConfigRef*(): ConfigRef = ## create a new ConfigRef that is only good enough for error reporting. @@ -215,11 +248,6 @@ var gExitcode*: int8 gCmd*: TCommands = cmdNone # the command gSelectedGC* = gcRefc # the selected GC - searchPaths*: seq[string] = @[] - lazyPaths*: seq[string] = @[] - outFile*: string = "" - docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \ - # The string uses the formatting variables `path` and `line`. #headerFile*: string = "" gVerbosity* = 1 # how verbose the compiler is gNumberOfProcessors*: int # number of processors @@ -262,24 +290,6 @@ const DocConfig* = "nimdoc.cfg" DocTexConfig* = "nimdoc.tex.cfg" -# additional configuration variables: -var - gDllOverrides = newStringTable(modeCaseInsensitive) - gModuleOverrides* = newStringTable(modeStyleInsensitive) - gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc. - libpath* = "" - gProjectName* = "" # holds a name like 'nim' - gProjectPath* = "" # holds a path like /home/alice/projects/nim/compiler/ - gProjectFull* = "" # projectPath/projectName - gProjectIsStdin* = false # whether we're compiling from stdin - gProjectMainIdx*: int32 # the canonical path id of the main module - nimcacheDir* = "" - command* = "" # the main command (e.g. cc, check, scan, etc) - commandArgs*: seq[string] = @[] # any arguments after the main command - gKeepComments*: bool = true # whether the parser needs to keep comments - implicitImports*: seq[string] = @[] # modules that are to be implicitly imported - implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included - const oKeepVariableNames* = true template compilingLib*(conf: ConfigRef): bool = @@ -289,10 +299,10 @@ proc mainCommandArg*(conf: ConfigRef): string = ## This is intended for commands like check or parse ## which will work on the main project file unless ## explicitly given a specific file argument - if commandArgs.len > 0: - result = commandArgs[0] + if conf.commandArgs.len > 0: + result = conf.commandArgs[0] else: - result = gProjectName + result = conf.projectName proc existsConfigVar*(conf: ConfigRef; key: string): bool = result = hasKey(conf.configVars, key) @@ -304,37 +314,36 @@ proc setConfigVar*(conf: ConfigRef; key, val: string) = conf.configVars[key] = val proc getOutFile*(conf: ConfigRef; filename, ext: string): string = - if options.outFile != "": result = options.outFile + if conf.outFile != "": result = conf.outFile else: result = changeFileExt(filename, ext) proc getPrefixDir*(conf: ConfigRef): string = ## Gets the prefix dir, usually the parent directory where the binary resides. ## - ## This is overridden by some tools (namely nimsuggest) via the ``gPrefixDir`` + ## This is overridden by some tools (namely nimsuggest) via the ``conf.prefixDir`` ## global. - if gPrefixDir != "": result = gPrefixDir - else: - result = splitPath(getAppDir()).head + if conf.prefixDir != "": result = conf.prefixDir + else: result = splitPath(getAppDir()).head proc setDefaultLibpath*(conf: ConfigRef) = # set default value (can be overwritten): - if libpath == "": + if conf.libpath == "": # choose default libpath: var prefix = getPrefixDir(conf) when defined(posix): - if prefix == "/usr": libpath = "/usr/lib/nim" - elif prefix == "/usr/local": libpath = "/usr/local/lib/nim" - else: libpath = joinPath(prefix, "lib") - else: libpath = joinPath(prefix, "lib") + if prefix == "/usr": conf.libpath = "/usr/lib/nim" + elif prefix == "/usr/local": conf.libpath = "/usr/local/lib/nim" + else: conf.libpath = joinPath(prefix, "lib") + else: conf.libpath = joinPath(prefix, "lib") # Special rule to support other tools (nimble) which import the compiler # modules and make use of them. let realNimPath = findExe("nim") # Find out if $nim/../../lib/system.nim exists. let parentNimLibPath = realNimPath.parentDir.parentDir / "lib" - if not fileExists(libpath / "system.nim") and + if not fileExists(conf.libpath / "system.nim") and fileExists(parentNimlibPath / "system.nim"): - libpath = parentNimLibPath + conf.libpath = parentNimLibPath proc canonicalizePath*(conf: ConfigRef; path: string): string = # on Windows, 'expandFilename' calls getFullPathName which doesn't do @@ -350,7 +359,7 @@ proc canonicalizePath*(conf: ConfigRef; path: string): string = proc shortenDir*(conf: ConfigRef; dir: string): string = ## returns the interesting part of a dir - var prefix = gProjectPath & DirSep + var prefix = conf.projectPath & DirSep if startsWith(dir, prefix): return substr(dir, len(prefix)) prefix = getPrefixDir(conf) & DirSep @@ -366,25 +375,24 @@ proc removeTrailingDirSep*(path: string): string = proc disableNimblePath*(conf: ConfigRef) = gNoNimblePath = true - lazyPaths.setLen(0) + conf.lazyPaths.setLen(0) include packagehandling proc getNimcacheDir*(conf: ConfigRef): string = - result = if nimcacheDir.len > 0: nimcacheDir else: shortenDir(conf, gProjectPath) / - genSubDir - + result = if conf.nimcacheDir.len > 0: conf.nimcacheDir + else: shortenDir(conf, conf.projectPath) / genSubDir proc pathSubs*(conf: ConfigRef; p, config: string): string = let home = removeTrailingDirSep(os.getHomeDir()) result = unixToNativePath(p % [ "nim", getPrefixDir(conf), - "lib", libpath, + "lib", conf.libpath, "home", home, "config", config, - "projectname", options.gProjectName, - "projectpath", options.gProjectPath, - "projectdir", options.gProjectPath, + "projectname", conf.projectName, + "projectpath", conf.projectPath, + "projectdir", conf.projectPath, "nimcache", getNimcacheDir(conf)]) if "~/" in result: result = result.replace("~/", home & '/') @@ -410,28 +418,28 @@ proc completeGeneratedFilePath*(conf: ConfigRef; f: string, createSubDir: bool = #echo "completeGeneratedFilePath(", f, ") = ", result proc rawFindFile(conf: ConfigRef; f: string): string = - for it in searchPaths: + for it in conf.searchPaths: result = joinPath(it, f) if existsFile(result): return canonicalizePath(conf, result) result = "" proc rawFindFile2(conf: ConfigRef; f: string): string = - for i, it in lazyPaths: + for i, it in conf.lazyPaths: result = joinPath(it, f) if existsFile(result): # bring to front for j in countDown(i,1): - swap(lazyPaths[j], lazyPaths[j-1]) + swap(conf.lazyPaths[j], conf.lazyPaths[j-1]) return canonicalizePath(conf, result) result = "" template patchModule(conf: ConfigRef) {.dirty.} = - if result.len > 0 and gModuleOverrides.len > 0: + if result.len > 0 and conf.moduleOverrides.len > 0: let key = getPackageName(conf, result) & "_" & splitFile(result).name - if gModuleOverrides.hasKey(key): - let ov = gModuleOverrides[key] + if conf.moduleOverrides.hasKey(key): + let ov = conf.moduleOverrides[key] if ov.len > 0: result = ov proc findFile*(conf: ConfigRef; f: string): string {.procvar.} = @@ -492,10 +500,10 @@ proc canonDynlibName(s: string): string = result = s.substr(start) proc inclDynlibOverride*(conf: ConfigRef; lib: string) = - gDllOverrides[lib.canonDynlibName] = "true" + conf.dllOverrides[lib.canonDynlibName] = "true" proc isDynlibOverride*(conf: ConfigRef; lib: string): bool = - result = gDynlibOverrideAll or gDllOverrides.hasKey(lib.canonDynlibName) + result = gDynlibOverrideAll or conf.dllOverrides.hasKey(lib.canonDynlibName) proc binaryStrSearch*(x: openArray[string], y: string): int = var a = 0 diff --git a/compiler/passes.nim b/compiler/passes.nim index 931bcc04bc..8f9f57f3de 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -216,8 +216,8 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, # modules to include between compilation runs? we'd need to track that # in ROD files. I think we should enable this feature only # for the interactive mode. - processImplicits graph.config, implicitImports, nkImportStmt, a, module - processImplicits graph.config, implicitIncludes, nkIncludeStmt, a, module + processImplicits graph.config, graph.config.implicitImports, nkImportStmt, a, module + processImplicits graph.config, graph.config.implicitIncludes, nkIncludeStmt, a, module while true: if graph.stopCompile(): break diff --git a/compiler/rodread.nim b/compiler/rodread.nim index c7fea29473..f62c24dfd5 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -918,7 +918,7 @@ proc handleSymbolFile*(module: PSym; cache: IdentCache; conf: ConfigRef): PRodRe if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}: module.id = getID() return nil - idgen.loadMaxIds(conf, options.gProjectPath / options.gProjectName) + idgen.loadMaxIds(conf, conf.projectPath / conf.projectName) let fileIdx = module.fileIdx discard checkDep(fileIdx, cache, conf) #if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile") diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index ae6e5c99fd..7dc10bbf56 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -653,7 +653,7 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = result = process(c, n) var w = PRodWriter(c) writeRod(w) - idgen.saveMaxIds(graph.config, options.gProjectPath / options.gProjectName) + idgen.saveMaxIds(graph.config, graph.config.projectPath / graph.config.projectName) const rodwritePass* = makePass(open = myOpen, close = myClose, process = process) From efc2ce1b7eeb07fb3b26b4f62eaa1b32aed744cf Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 11 May 2018 16:06:36 +0200 Subject: [PATCH 182/214] docgen compiles again --- compiler/docgen.nim | 129 ++++++++++++++++++---------------- lib/packages/docutils/rst.nim | 4 +- 2 files changed, 69 insertions(+), 64 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index a21c8073f0..7fca27cc9e 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -29,6 +29,7 @@ type jArray: JsonNode types: TStrTable isPureRst: bool + conf: ConfigRef PDoc* = ref TDocumentor ## Alias to type less. @@ -88,11 +89,12 @@ proc parseRst(text, filename: string, proc newDocumentor*(filename: string, conf: ConfigRef): PDoc = declareClosures() new(result) + result.conf = conf initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex), - options.gConfigVars, filename, {roSupportRawDirective}, + conf.configVars, filename, {roSupportRawDirective}, docgenFindFile, compilerMsgHandler) - if config.hasKey("doc.googleAnalytics"): + if conf.configVars.hasKey("doc.googleAnalytics"): result.analytics = """ - """ % [config.getOrDefault"doc.googleAnalytics"] + """ % [conf.configVars.getOrDefault"doc.googleAnalytics"] else: result.analytics = "" @@ -125,7 +127,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int = return i result = -1 -proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string], +proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr, + varnames: openArray[string], varvalues: openArray[Rope]): Rope = var i = 0 var L = len(frmt) @@ -148,7 +151,8 @@ proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string], j = (j * 10) + ord(frmt[i]) - ord('0') inc(i) if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break - if j > high(varvalues) + 1: internalError("ropeFormatNamedVars") + if j > high(varvalues) + 1: + rawMessage(conf, errGenerated, "Invalid format string; too many $s: " & frmt) num = j add(result, varvalues[j - 1]) of 'A'..'Z', 'a'..'z', '\x80'..'\xFF': @@ -159,20 +163,23 @@ proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string], if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break var idx = getVarIdx(varnames, id) if idx >= 0: add(result, varvalues[idx]) - else: rawMessage(errUnknownSubstitionVar, id) + else: rawMessage(conf, errGenerated, "unknown substition variable: " & id) of '{': var id = "" inc(i) - while frmt[i] != '}': - if frmt[i] == '\0': rawMessage(errTokenExpected, "}") + while i < frmt.len and frmt[i] != '}': add(id, frmt[i]) inc(i) - inc(i) # skip } - # search for the variable: - var idx = getVarIdx(varnames, id) + if i >= frmt.len: + rawMessage(conf, errGenerated, "expected closing '}'") + else: + inc(i) # skip } + # search for the variable: + let idx = getVarIdx(varnames, id) if idx >= 0: add(result, varvalues[idx]) - else: rawMessage(errUnknownSubstitionVar, id) - else: internalError("ropeFormatNamedVars") + else: rawMessage(conf, errGenerated, "unknown substition variable: " & id) + else: + add(result, "$") var start = i while i < L: if frmt[i] != '$': inc(i) @@ -185,7 +192,7 @@ proc genComment(d: PDoc, n: PNode): string = if n.comment != nil: renderRstToOut(d[], parseRst(n.comment, toFilename(n.info), toLinenumber(n.info), toColumn(n.info), - dummyHasToc, d.options), result) + dummyHasToc, d.options, d.conf), result) proc genRecComment(d: PDoc, n: PNode): Rope = if n == nil: return nil @@ -340,7 +347,6 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string = of nkOpenSymChoice, nkClosedSymChoice: result = getName(d, n[0], splitAfter) else: - internalError(n.info, "getName()") result = "" proc getNameIdent(n: PNode): PIdent = @@ -370,7 +376,6 @@ proc getRstName(n: PNode): PRstNode = of nkOpenSymChoice, nkClosedSymChoice: result = getRstName(n[0]) else: - internalError(n.info, "getRstName()") result = nil proc newUniquePlainSymbol(d: PDoc, original: string): string = @@ -494,22 +499,22 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = symbolOrIdEncRope = encodeUrl(symbolOrId).rope var seeSrcRope: Rope = nil - let docItemSeeSrc = getConfigVar("doc.item.seesrc") + let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc") if docItemSeeSrc.len > 0: - let cwd = getCurrentDir().canonicalizePath() + let cwd = canonicalizePath(d.conf, getCurrentDir()) var path = n.info.toFullPath if path.startsWith(cwd): path = path[cwd.len+1 .. ^1].replace('\\', '/') - let gitUrl = getConfigVar("git.url") + let gitUrl = getConfigVar(d.conf, "git.url") if gitUrl.len > 0: - var commit = getConfigVar("git.commit") + var commit = getConfigVar(d.conf, "git.commit") if commit.len == 0: commit = "master" - dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc, + dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc, ["path", "line", "url", "commit"], [rope path, rope($n.info.line), rope gitUrl, rope commit])]) - add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"), + add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"), ["name", "header", "desc", "itemID", "header_plain", "itemSym", "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"], [nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope, @@ -520,7 +525,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = let att = attachToType(d, nameNode.sym) if att != nil: attype = rope esc(d.target, att.name.s) - add(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"), + add(d.toc[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"), ["name", "header", "desc", "itemID", "header_plain", "itemSym", "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"], [rope(getName(d, nameNode, d.splitAfter)), result, comm, @@ -575,7 +580,7 @@ proc traceDeps(d: PDoc, it: PNode) = if d.section[k] != nil: add(d.section[k], ", ") dispA(d.section[k], "$1", - "$1", [rope(getModuleName(it))]) + "$1", [rope(getModuleName(d.conf, it))]) proc generateDoc*(d: PDoc, n: PNode) = case n.kind @@ -708,10 +713,10 @@ proc genSection(d: PDoc, kind: TSymKind) = ] if d.section[kind] == nil: return var title = sectionNames[kind].rope - d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [ + d.section[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section"), [ "sectionid", "sectionTitle", "sectionTitleID", "content"], [ ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]]) - d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [ + d.toc[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section.toc"), [ "sectionid", "sectionTitle", "sectionTitleID", "content"], [ ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]]) @@ -727,7 +732,7 @@ proc genOutFile(d: PDoc): Rope = genSection(d, i) add(toc, d.toc[i]) if toc != nil: - toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc]) + toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc]) for i in countup(low(TSymKind), high(TSymKind)): add(code, d.section[i]) # Extract the title. Non API modules generate an entry in the index table. @@ -741,13 +746,13 @@ proc genOutFile(d: PDoc): Rope = let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group" elif d.hasToc: "doc.body_toc" else: "doc.body_no_toc" - content = ropeFormatNamedVars(getConfigVar(bodyname), ["title", + content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title", "tableofcontents", "moduledesc", "date", "time", "content"], [title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()), code]) if optCompileOnly notin gGlobalOptions: # XXX what is this hack doing here? 'optCompileOnly' means raw output!? - code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title", + code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), ["title", "tableofcontents", "moduledesc", "date", "time", "content", "author", "version", "analytics"], [title.rope, toc, d.modDesc, rope(getDateStr()), @@ -759,59 +764,59 @@ proc genOutFile(d: PDoc): Rope = proc generateIndex*(d: PDoc) = if optGenIndex in gGlobalOptions: - writeIndexFile(d[], splitFile(options.outFile).dir / + writeIndexFile(d[], splitFile(d.conf.outFile).dir / splitFile(d.filename).name & IndexExt) -proc getOutFile2(filename, ext, dir: string): string = +proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string = if gWholeProject: - let d = if options.outFile != "": options.outFile else: dir + let d = if conf.outFile != "": conf.outFile else: dir createDir(d) result = d / changeFileExt(filename, ext) else: - result = getOutFile(filename, ext) + result = getOutFile(conf, filename, ext) proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) = var content = genOutFile(d) if optStdout in gGlobalOptions: writeRope(stdout, content) else: - writeRope(content, getOutFile2(filename, outExt, "htmldocs"), useWarning) + writeRope(content, getOutFile2(d.conf, filename, outExt, "htmldocs"), useWarning) proc writeOutputJson*(d: PDoc, filename, outExt: string, useWarning = false) = let content = %*{"orig": d.filename, - "nimble": getPackageName(d.filename), + "nimble": getPackageName(d.conf, d.filename), "entries": d.jArray} if optStdout in gGlobalOptions: write(stdout, $content) else: var f: File - if open(f, getOutFile2(splitFile(filename).name, + if open(f, getOutFile2(d.conf, splitFile(filename).name, outExt, "jsondocs"), fmWrite): write(f, $content) close(f) else: discard "fixme: error report" -proc commandDoc*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) +proc commandDoc*(conf: ConfigRef) = + var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf) if ast == nil: return - var d = newDocumentor(gProjectFull, options.gConfigVars) + var d = newDocumentor(conf.projectFull, conf) d.hasToc = true generateDoc(d, ast) - writeOutput(d, gProjectFull, HtmlExt) + writeOutput(d, conf.projectFull, HtmlExt) generateIndex(d) -proc commandRstAux(filename, outExt: string) = +proc commandRstAux(conf: ConfigRef; filename, outExt: string) = var filen = addFileExt(filename, "txt") - var d = newDocumentor(filen, options.gConfigVars) + var d = newDocumentor(filen, conf) d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) = var outp: string if filename.len == 0: inc(d.id) let nameOnly = splitFile(d.filename).name - let subdir = getNimcacheDir() / nameOnly + let subdir = getNimcacheDir(conf) / nameOnly createDir(subdir) outp = subdir / (nameOnly & "_snippet_" & $d.id & ".nim") elif isAbsolute(filename): @@ -821,13 +826,13 @@ proc commandRstAux(filename, outExt: string) = outp = splitFile(d.filename).dir / filename writeFile(outp, content) let cmd = cmd % quoteShell(outp) - rawMessage(hintExecuting, cmd) + rawMessage(conf, hintExecuting, cmd) if execShellCmd(cmd) != status: - rawMessage(errExecutionOfProgramFailed, cmd) + rawMessage(conf, errGenerated, "executing of external program failed: " & cmd) d.isPureRst = true var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc, - {roSupportRawDirective}) + {roSupportRawDirective}, conf) var modDesc = newStringOfCap(30_000) #d.modDesc = newMutableRope(30_000) renderRstToOut(d[], rst, modDesc) @@ -836,17 +841,17 @@ proc commandRstAux(filename, outExt: string) = writeOutput(d, filename, outExt) generateIndex(d) -proc commandRst2Html*() = - commandRstAux(gProjectFull, HtmlExt) +proc commandRst2Html*(conf: ConfigRef) = + commandRstAux(conf, conf.projectFull, HtmlExt) -proc commandRst2TeX*() = +proc commandRst2TeX*(conf: ConfigRef) = splitter = "\\-" - commandRstAux(gProjectFull, TexExt) + commandRstAux(conf, conf.projectFull, TexExt) -proc commandJson*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) +proc commandJson*(conf: ConfigRef) = + var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf) if ast == nil: return - var d = newDocumentor(gProjectFull, options.gConfigVars) + var d = newDocumentor(conf.projectFull, conf) d.hasToc = true generateJson(d, ast) let json = d.jArray @@ -856,12 +861,12 @@ proc commandJson*() = writeRope(stdout, content) else: #echo getOutFile(gProjectFull, JsonExt) - writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false) + writeRope(content, getOutFile(conf, conf.projectFull, JsonExt), useWarning = false) -proc commandTags*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) +proc commandTags*(conf: ConfigRef) = + var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf) if ast == nil: return - var d = newDocumentor(gProjectFull, options.gConfigVars) + var d = newDocumentor(conf.projectFull, conf) d.hasToc = true var content: Rope @@ -871,15 +876,15 @@ proc commandTags*() = writeRope(stdout, content) else: #echo getOutFile(gProjectFull, TagsExt) - writeRope(content, getOutFile(gProjectFull, TagsExt), useWarning = false) + writeRope(content, getOutFile(conf, conf.projectFull, TagsExt), useWarning = false) -proc commandBuildIndex*() = - var content = mergeIndexes(gProjectFull).rope +proc commandBuildIndex*(conf: ConfigRef) = + var content = mergeIndexes(conf.projectFull).rope - let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title", + let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), ["title", "tableofcontents", "moduledesc", "date", "time", "content", "author", "version", "analytics"], ["Index".rope, nil, nil, rope(getDateStr()), rope(getClockStr()), content, nil, nil, nil]) # no analytics because context is not available - writeRope(code, getOutFile("theindex", HtmlExt)) + writeRope(code, getOutFile(conf, "theindex", HtmlExt)) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index ff2bdb8ce9..adac167774 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -43,8 +43,8 @@ type mwUnsupportedField MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind, - arg: string) {.nimcall.} ## what to do in case of an error - FindFileHandler* = proc (filename: string): string {.nimcall.} + arg: string) {.closure.} ## what to do in case of an error + FindFileHandler* = proc (filename: string): string {.closure.} const messages: array[MsgKind, string] = [ From 84bc04ba3281b67327a9c02c678890d0386efd12 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 11 May 2018 18:04:11 +0200 Subject: [PATCH 183/214] sigmatch compiles again --- compiler/configuration.nim | 2 +- compiler/sigmatch.nim | 86 +++++++++++++++++++------------------- compiler/suggest.nim | 36 ++++++++-------- 3 files changed, 63 insertions(+), 61 deletions(-) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index 5164fd6df9..44345186d4 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -385,7 +385,7 @@ errXhasSideEffects: "'$1' can have side effects", errIteratorExpected: "iterator within for loop context expected", errLetNeedsInit: "'let' symbol requires an initialization", errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread", -errWrongSymbolX: "usage of '$1' is a user-defined error", +errWrongSymbolX:, errIllegalCaptureX: "illegal capture '$1'", errXCannotBeClosure: "'$1' cannot have 'closure' calling convention", errXMustBeCompileTime: "'$1' can only be used in compile-time context", diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4263ef5813..01413f6788 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -99,7 +99,7 @@ type const isNilConversion = isConvertible # maybe 'isIntConv' fits better? -proc markUsed*(info: TLineInfo, s: PSym; usageSym: var PSym) +proc markUsed*(conf: ConfigRef; info: TLineInfo, s: PSym; usageSym: var PSym) template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone @@ -152,13 +152,13 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1): var formalTypeParam = typeParams.sons[i-1].typ var bound = binding[i].typ - internalAssert bound != nil - if formalTypeParam.kind == tyTypeDesc: - if bound.kind != tyTypeDesc: - bound = makeTypeDesc(ctx, bound) - else: - bound = bound.skipTypes({tyTypeDesc}) - put(c, formalTypeParam, bound) + if bound != nil: + if formalTypeParam.kind == tyTypeDesc: + if bound.kind != tyTypeDesc: + bound = makeTypeDesc(ctx, bound) + else: + bound = bound.skipTypes({tyTypeDesc}) + put(c, formalTypeParam, bound) proc newCandidate*(ctx: PContext, callee: PSym, binding: PNode, calleeScope = -1): TCandidate = @@ -362,8 +362,8 @@ proc concreteType(c: TCandidate, t: PType): PType = # proc sort[T](cmp: proc(a, b: T): int = cmp) if result.kind != tyGenericParam: break of tyGenericInvocation: - internalError("cannot resolve type: " & typeToString(t)) result = t + doAssert(false, "cannot resolve type: " & typeToString(t)) else: result = t # Note: empty is valid here @@ -519,8 +519,8 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation = if f.n != nil and a.n != nil: for i in countup(0, sonsLen(f.n) - 1): # check field names: - if f.n.sons[i].kind != nkSym: internalError(f.n.info, "recordRel") - elif a.n.sons[i].kind != nkSym: internalError(a.n.info, "recordRel") + if f.n.sons[i].kind != nkSym: return isNone + elif a.n.sons[i].kind != nkSym: return isNone else: var x = f.n.sons[i].sym var y = a.n.sons[i].sym @@ -661,7 +661,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = matchedConceptContext.prev = prevMatchedConcept matchedConceptContext.depth = prevMatchedConcept.depth + 1 if prevMatchedConcept.depth > 4: - localError(body.info, $body & " too nested for type matching") + localError(m.c.graph.config, body.info, $body & " too nested for type matching") return nil openScope(c) @@ -760,19 +760,20 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = result.n = checkedBody -proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool = +proc shouldSkipDistinct(m: TCandidate; rules: PNode, callIdent: PIdent): bool = + # XXX This is bad as 'considerQuotedIdent' can produce an error! if rules.kind == nkWith: for r in rules: - if r.considerQuotedIdent == callIdent: return true + if considerQuotedIdent(m.c.graph.config, r) == callIdent: return true return false else: for r in rules: - if r.considerQuotedIdent == callIdent: return false + if considerQuotedIdent(m.c.graph.config, r) == callIdent: return false return true -proc maybeSkipDistinct(t: PType, callee: PSym): PType = +proc maybeSkipDistinct(m: TCandidate; t: PType, callee: PSym): PType = if t != nil and t.kind == tyDistinct and t.n != nil and - shouldSkipDistinct(t.n, callee.name): + shouldSkipDistinct(m, t.n, callee.name): result = t.base else: result = t @@ -868,11 +869,11 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool = return false -proc failureToInferStaticParam(n: PNode) = +proc failureToInferStaticParam(conf: ConfigRef; n: PNode) = let staticParam = n.findUnresolvedStatic let name = if staticParam != nil: staticParam.sym.name.s else: "unknown" - localError(n.info, errCannotInferStaticParam, name) + localError(conf, n.info, "cannot infer the value of the static param '" & name & "'") proc inferStaticsInRange(c: var TCandidate, inferred, concrete: PType): TTypeRelation = @@ -886,7 +887,7 @@ proc inferStaticsInRange(c: var TCandidate, if inferStaticParam(c, exp, rhs): return isGeneric else: - failureToInferStaticParam exp + failureToInferStaticParam(c.c.graph.config, exp) if lowerBound.kind == nkIntLit: if upperBound.kind == nkIntLit: @@ -999,7 +1000,8 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, of tyStatic: candidate = computedType else: - localError(f.n.info, errTypeExpected) + # XXX What is this non-sense? Error reporting in signature matching? + discard "localError(f.n.info, errTypeExpected)" else: discard @@ -1013,7 +1015,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, template doBind: bool = trDontBind notin flags # var and static arguments match regular modifier-free types - var a = aOrig.skipTypes({tyStatic, tyVar, tyLent}).maybeSkipDistinct(c.calleeSym) + var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyLent}), c.calleeSym) # XXX: Theoretically, maybeSkipDistinct could be called before we even # start the param matching process. This could be done in `prepareOperand` # for example, but unfortunately `prepareOperand` is not called in certain @@ -1442,7 +1444,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, (sonsLen(x) - 1 == sonsLen(f)): for i in countup(1, sonsLen(f) - 1): if x.sons[i].kind == tyGenericParam: - internalError("wrong instantiated type!") + internalError(c.c.graph.config, "wrong instantiated type!") elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: # Workaround for regression #4589 if f.sons[i].kind != tyTypeDesc: return @@ -1474,7 +1476,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, if x == nil: discard "maybe fine (for eg. a==tyNil)" elif x.kind in {tyGenericInvocation, tyGenericParam}: - internalError("wrong instantiated type!") + internalError(c.c.graph.config, "wrong instantiated type!") else: put(c, f.sons[i], x) @@ -1597,7 +1599,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, if f.sonsLen == 0: result = isGeneric else: - internalAssert a.sons != nil and a.sons.len > 0 + internalAssert c.c.graph.config, a.sons != nil and a.sons.len > 0 c.typedescMatched = true var aa = a while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0: @@ -1739,13 +1741,13 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n): result = isNone else: - localError(f.n.info, errTypeExpected) + localError(c.c.graph.config, f.n.info, "type expected") result = isNone of tyNone: if a.kind == tyNone: result = isEqual else: - internalError " unknown type kind " & $f.kind + internalError c.c.graph.config, " unknown type kind " & $f.kind proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = var m: TCandidate @@ -1758,7 +1760,7 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, if result == nil: result = generateTypeInstance(c, m.bindings, arg, f) if result == nil: - internalError(arg.info, "getInstantiatedType") + internalError(c.graph.config, arg.info, "getInstantiatedType") result = errorType(c) proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, @@ -1771,7 +1773,7 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, result.typ = errorType(c) else: result.typ = f - if result.typ == nil: internalError(arg.info, "implicitConv") + if result.typ == nil: internalError(c.graph.config, arg.info, "implicitConv") addSon(result, ast.emptyNode) addSon(result, arg) @@ -1792,7 +1794,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, dest = generateTypeInstance(c, m.bindings, arg, dest) let fdest = typeRel(m, f, dest) if fdest in {isEqual, isGeneric}: - markUsed(arg.info, c.converters[i], c.graph.usageSym) + markUsed(c.config, arg.info, c.converters[i], c.graph.usageSym) var s = newSymNode(c.converters[i]) s.typ = c.converters[i].typ s.info = arg.info @@ -2066,7 +2068,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, result = nil elif y.state == csMatch and cmpCandidates(x, y) == 0: if x.state != csMatch: - internalError(arg.info, "x.state is not csMatch") + internalError(m.c.graph.config, arg.info, "x.state is not csMatch") # ambiguous: more than one symbol fits! # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match # anyway: @@ -2074,12 +2076,11 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, else: result = nil else: # only one valid interpretation found: - markUsed(arg.info, arg.sons[best].sym, m.c.graph.usageSym) + markUsed(m.c.config, arg.info, arg.sons[best].sym, m.c.graph.usageSym) styleCheckUse(arg.info, arg.sons[best].sym) result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], argOrig) - proc setSon(father: PNode, at: int, son: PNode) = let oldLen = father.len if oldLen <= at: @@ -2115,10 +2116,10 @@ proc prepareOperand(c: PContext; a: PNode): PNode = result = a considerGenSyms(c, result) -proc prepareNamedParam(a: PNode) = +proc prepareNamedParam(a: PNode; conf: ConfigRef) = if a.sons[0].kind != nkIdent: var info = a.sons[0].info - a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info) + a.sons[0] = newIdentNode(considerQuotedIdent(conf, a.sons[0]), info) proc arrayConstr(c: PContext, n: PNode): PType = result = newTypeS(tyArray, c) @@ -2182,9 +2183,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, elif n.sons[a].kind == nkExprEqExpr: # named param # check if m.callee has such a param: - prepareNamedParam(n.sons[a]) + prepareNamedParam(n.sons[a], c.config) if n.sons[a].sons[0].kind != nkIdent: - localError(n.sons[a].info, errNamedParamHasToBeIdent) + localError(c.config, n.sons[a].info, "named parameter has to be an identifier") m.state = csNoMatch return formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1) @@ -2227,8 +2228,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, # we have no formal here to snoop at: n.sons[a] = prepareOperand(c, n.sons[a]) if skipTypes(n.sons[a].typ, abstractVar-{tyTypeDesc}).kind==tyString: - addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString), - copyTree(n.sons[a]), m, c)) + addSon(m.call, implicitConv(nkHiddenStdConv, + getSysType(c.graph, n.sons[a].info, tyCString), + copyTree(n.sons[a]), m, c)) else: addSon(m.call, copyTree(n.sons[a])) elif formal != nil and formal.typ.kind == tyVarargs: @@ -2251,7 +2253,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, return else: if m.callee.n.sons[f].kind != nkSym: - internalError(n.sons[a].info, "matches") + internalError(c.config, n.sons[a].info, "matches") return formal = m.callee.n.sons[f].sym if containsOrIncl(marker, formal.position) and container.isNil: @@ -2359,7 +2361,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; var m: TCandidate initCandidate(c, m, dc.typ) if col >= dc.typ.len: - localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'") + localError(c.config, info, "cannot instantiate '" & dc.name.s & "'") return nil var f = dc.typ.sons[col] @@ -2368,7 +2370,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; else: if f.kind == tyVar: f = f.lastSon if typeRel(m, f, t) == isNone: - localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'") + localError(c.config, info, "cannot instantiate '" & dc.name.s & "'") else: result = c.semGenerateInstance(c, dc, m.bindings, info) if op == attachedDeepCopy: diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 555ec98677..82b6038a43 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -32,7 +32,7 @@ # included from sigmatch.nim -import algorithm, prefixmatches +import algorithm, prefixmatches, configuration from wordrecg import wDeprecated when defined(nimsuggest): @@ -192,8 +192,8 @@ proc suggestResult(s: Suggest) = else: suggestWriteln($s) -proc produceOutput(a: var Suggestions) = - if gIdeCmd in {ideSug, ideCon}: +proc produceOutput(a: var Suggestions; conf: ConfigRef) = + if conf.ideCmd in {ideSug, ideCon}: a.sort cmpSuggestions when defined(debug): # debug code @@ -480,30 +480,30 @@ proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.in isDecl: suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) -proc warnAboutDeprecated(info: TLineInfo; s: PSym) = +proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) = if s.kind in routineKinds: let n = s.ast[pragmasPos] if n.kind != nkEmpty: for it in n: if whichPragma(it) == wDeprecated and it.safeLen == 2 and it[1].kind in {nkStrLit..nkTripleStrLit}: - message(info, warnDeprecated, it[1].strVal & "; " & s.name.s) + message(conf, info, warnDeprecated, it[1].strVal & "; " & s.name.s) return - message(info, warnDeprecated, s.name.s) + message(conf, info, warnDeprecated, s.name.s) -proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) = +proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = incl(s.flags, sfUsed) if s.kind == skEnumField and s.owner != nil: incl(s.owner.flags, sfUsed) if {sfDeprecated, sfError} * s.flags != {}: - if sfDeprecated in s.flags: warnAboutDeprecated(info, s) - if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s) + if sfDeprecated in s.flags: warnAboutDeprecated(conf, info, s) + if sfError in s.flags: localError(conf, info, "usage of '$1' is a user-defined error" % s.name.s) when defined(nimsuggest): suggestSym(info, s, usageSym, false) -proc useSym*(sym: PSym; usageSym: var PSym): PNode = +proc useSym*(conf: ConfigRef; sym: PSym; usageSym: var PSym): PNode = result = newSymNode(sym) - markUsed(result.info, sym, usageSym) + markUsed(conf, result.info, sym, usageSym) proc safeSemExpr*(c: PContext, n: PNode): PNode = # use only for idetools support! @@ -534,9 +534,9 @@ proc suggestExprNoCheck*(c: PContext, n: PNode) = if c.compilesContextId > 0: return inc(c.compilesContextId) var outputs: Suggestions = @[] - if gIdeCmd == ideSug: + if c.config.ideCmd == ideSug: sugExpr(c, n, outputs) - elif gIdeCmd == ideCon: + elif c.config.ideCmd == ideCon: if n.kind in nkCallKinds: var a = copyNode(n) var x = safeSemExpr(c, n.sons[0]) @@ -550,8 +550,8 @@ proc suggestExprNoCheck*(c: PContext, n: PNode) = suggestCall(c, a, n, outputs) dec(c.compilesContextId) - if outputs.len > 0 and gIdeCmd in {ideSug, ideCon, ideDef}: - produceOutput(outputs) + if outputs.len > 0 and c.config.ideCmd in {ideSug, ideCon, ideDef}: + produceOutput(outputs, c.config) suggestQuit() proc suggestExpr*(c: PContext, n: PNode) = @@ -570,11 +570,11 @@ proc suggestStmt*(c: PContext, n: PNode) = proc suggestEnum*(c: PContext; n: PNode; t: PType) = var outputs: Suggestions = @[] suggestSymList(c, t.n, nil, n.info, outputs) - produceOutput(outputs) + produceOutput(outputs, c.config) if outputs.len > 0: suggestQuit() proc suggestSentinel*(c: PContext) = - if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return + if c.config.ideCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return if c.compilesContextId > 0: return inc(c.compilesContextId) var outputs: Suggestions = @[] @@ -590,4 +590,4 @@ proc suggestSentinel*(c: PContext) = outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN)) dec(c.compilesContextId) - produceOutput(outputs) + produceOutput(outputs, c.config) From bb8c47b496131a64aa9fa25ac4d538807397b102 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 11 May 2018 18:53:18 +0200 Subject: [PATCH 184/214] pragmas compiles again --- compiler/cgmeth.nim | 45 ++-- compiler/configuration.nim | 4 +- compiler/importer.nim | 34 +-- compiler/pragmas.nim | 444 +++++++++++++++++++------------------ compiler/procfind.nim | 14 +- 5 files changed, 272 insertions(+), 269 deletions(-) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 0513e88f42..1d72952e20 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -11,9 +11,9 @@ import intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, - sempass2, strutils, modulegraphs + sempass2, strutils, modulegraphs, configuration -proc genConv(n: PNode, d: PType, downcast: bool): PNode = +proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode = var dest = skipTypes(d, abstractPtrs) var source = skipTypes(n.typ, abstractPtrs) if (source.kind == tyObject) and (dest.kind == tyObject): @@ -24,12 +24,12 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode = elif diff < 0: result = newNodeIT(nkObjUpConv, n.info, d) addSon(result, n) - if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed") + if downcast: internalError(conf, n.info, "cgmeth.genConv: no upcast allowed") elif diff > 0: result = newNodeIT(nkObjDownConv, n.info, d) addSon(result, n) if not downcast: - internalError(n.info, "cgmeth.genConv: no downcast allowed") + internalError(conf, n.info, "cgmeth.genConv: no downcast allowed") else: result = n else: @@ -42,7 +42,7 @@ proc getDispatcher*(s: PSym): PSym = let disp = dispn.sym if sfDispatcher in disp.flags: result = disp -proc methodCall*(n: PNode): PNode = +proc methodCall*(n: PNode; conf: ConfigRef): PNode = result = n # replace ordinary method by dispatcher method: let disp = getDispatcher(result.sons[0].sym) @@ -50,9 +50,9 @@ proc methodCall*(n: PNode): PNode = result.sons[0].sym = disp # change the arguments to up/downcasts to fit the dispatcher's parameters: for i in countup(1, sonsLen(result)-1): - result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true) + result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true, conf) else: - localError(n.info, "'" & $result.sons[0] & "' lacks a dispatcher") + localError(conf, n.info, "'" & $result.sons[0] & "' lacks a dispatcher") type MethodResult = enum No, Invalid, Yes @@ -130,7 +130,7 @@ proc createDispatcher(s: PSym): PSym = attachDispatcher(disp, newSymNode(disp)) return disp -proc fixupDispatcher(meth, disp: PSym) = +proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) = # We may have constructed the dispatcher from a method prototype # and need to augment the incomplete dispatcher with information # from later definitions, particularly the resultPos slot. Also, @@ -149,7 +149,7 @@ proc fixupDispatcher(meth, disp: PSym) = disp.typ.lockLevel = meth.typ.lockLevel elif meth.typ.lockLevel != UnspecifiedLockLevel and meth.typ.lockLevel != disp.typ.lockLevel: - message(meth.info, warnLockLevel, + message(conf, meth.info, warnLockLevel, "method has lock level $1, but another method has $2" % [$meth.typ.lockLevel, $disp.typ.lockLevel]) # XXX The following code silences a duplicate warning in @@ -166,13 +166,13 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) = of Yes: add(g.methods[i].methods, s) attachDispatcher(s, lastSon(disp.ast)) - fixupDispatcher(s, disp) + fixupDispatcher(s, disp, g.config) #echo "fixup ", disp.name.s, " ", disp.id - when useEffectSystem: checkMethodEffects(disp, s) + when useEffectSystem: checkMethodEffects(g, disp, s) if {sfBase, sfFromGeneric} * s.flags == {sfBase} and g.methods[i].methods[0] != s: # already exists due to forwarding definition? - localError(s.info, "method is not a base") + localError(g.config, s.info, "method is not a base") return of No: discard of Invalid: @@ -183,10 +183,10 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) = #if fromCache: # internalError(s.info, "no method dispatcher found") if witness != nil: - localError(s.info, "invalid declaration order; cannot attach '" & s.name.s & + localError(g.config, s.info, "invalid declaration order; cannot attach '" & s.name.s & "' to method defined here: " & $witness.info) elif sfBase notin s.flags: - message(s.info, warnUseBase) + message(g.config, s.info, warnUseBase) proc relevantCol(methods: TSymSeq, col: int): bool = # returns true iff the position is relevant @@ -225,32 +225,33 @@ proc sortBucket(a: var TSymSeq, relevantCols: IntSet) = a[j] = v if h == 1: break -proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym = +proc genDispatcher(g: ModuleGraph; methods: TSymSeq, relevantCols: IntSet): PSym = var base = lastSon(methods[0].ast).sym result = base var paramLen = sonsLen(base.typ) var nilchecks = newNodeI(nkStmtList, base.info) var disp = newNodeI(nkIfStmt, base.info) - var ands = getSysSym("and") - var iss = getSysSym("of") + var ands = getSysSym(g, unknownLineInfo(), "and") + var iss = getSysSym(g, unknownLineInfo(), "of") + let boolType = getSysType(g, unknownLineInfo(), tyBool) for col in countup(1, paramLen - 1): if contains(relevantCols, col): let param = base.typ.n.sons[col].sym if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}: addSon(nilchecks, newTree(nkCall, - newSymNode(getCompilerProc"chckNilDisp"), newSymNode(param))) + newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(param))) for meth in countup(0, high(methods)): var curr = methods[meth] # generate condition: var cond: PNode = nil for col in countup(1, paramLen - 1): if contains(relevantCols, col): - var isn = newNodeIT(nkCall, base.info, getSysType(tyBool)) + var isn = newNodeIT(nkCall, base.info, boolType) addSon(isn, newSymNode(iss)) let param = base.typ.n.sons[col].sym addSon(isn, newSymNode(param)) addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col])) if cond != nil: - var a = newNodeIT(nkCall, base.info, getSysType(tyBool)) + var a = newNodeIT(nkCall, base.info, boolType) addSon(a, newSymNode(ands)) addSon(a, cond) addSon(a, isn) @@ -262,7 +263,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym = addSon(call, newSymNode(curr)) for col in countup(1, paramLen - 1): addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym), - curr.typ.sons[col], false)) + curr.typ.sons[col], false, g.config)) var ret: PNode if retTyp != nil: var a = newNodeI(nkFastAsgn, base.info) @@ -290,4 +291,4 @@ proc generateMethodDispatchers*(g: ModuleGraph): PNode = if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col) sortBucket(g.methods[bucket].methods, relevantCols) addSon(result, - newSymNode(genDispatcher(g.methods[bucket].methods, relevantCols))) + newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols))) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index 44345186d4..b2548eb742 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -221,7 +221,7 @@ errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier", errTypeExpected: "type expected", errSystemNeeds: "system module needs '$1'", errExecutionOfProgramFailed: "execution of an external program failed: '$1'", -errNotOverloadable: "overloaded '$1' leads to ambiguous calls", +errNotOverloadable: , errInvalidArgForX: "invalid argument for '$1'", errStmtHasNoEffect: "statement has no effect", errXExpectsTypeOrValue: "'$1' expects a type or value", @@ -305,7 +305,7 @@ errInvalidOrderInEnumX: "invalid order in enum '$1'", errEnumXHasHoles: "enum '$1' has holes", errExceptExpected: "'except' or 'finally' expected", errInvalidTry: "after catch all 'except' or 'finally' no section may follow", -errOptionExpected: "option expected, but found '$1'", +errOptionExpected: , errXisNoLabel: "'$1' is not a label", errNotAllCasesCovered: "not all cases are covered", errUnknownSubstitionVar: "unknown substitution variable: '$1'", diff --git a/compiler/importer.nim b/compiler/importer.nim index f4903e6c48..05beb1d983 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -11,7 +11,7 @@ import intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups, - semdata, passes, renderer, modulepaths, sigmatch + semdata, passes, renderer, modulepaths, sigmatch, configuration proc evalImport*(c: PContext, n: PNode): PNode proc evalFrom*(c: PContext, n: PNode): PNode @@ -40,7 +40,7 @@ proc rawImportSymbol(c: PContext, s: PSym) = for j in countup(0, sonsLen(etyp.n) - 1): var e = etyp.n.sons[j].sym if e.kind != skEnumField: - internalError(s.info, "rawImportSymbol") + internalError(c.config, s.info, "rawImportSymbol") # BUGFIX: because of aliases for enums the symbol may already # have been put into the symbol table # BUGFIX: but only iff they are the same symbols! @@ -62,14 +62,14 @@ proc rawImportSymbol(c: PContext, s: PSym) = if hasPattern(s): addPattern(c, s) proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = - let ident = lookups.considerQuotedIdent(n) + let ident = lookups.considerQuotedIdent(c.config, n) let s = strTableGet(fromMod.tab, ident) if s == nil: errorUndeclaredIdentifier(c, n.info, ident.s) else: if s.kind == skStub: loadStub(s) if s.kind notin ExportableSymKinds: - internalError(n.info, "importSymbol: 2") + internalError(c.config, n.info, "importSymbol: 2") # for an enumeration we have to add all identifiers case s.kind of skProcKinds: @@ -77,7 +77,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = var it: TIdentIter var e = initIdentIter(it, fromMod.tab, s.name) while e != nil: - if e.name.id != s.name.id: internalError(n.info, "importSymbol: 3") + if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3") rawImportSymbol(c, e) e = nextIdentIter(it, fromMod.tab) else: rawImportSymbol(c, s) @@ -89,7 +89,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = if s.kind != skModule: if s.kind != skEnumField: if s.kind notin ExportableSymKinds: - internalError(s.info, "importAllSymbols: " & $s.kind) + internalError(c.config, s.info, "importAllSymbols: " & $s.kind) if exceptSet.isNil or s.name.id notin exceptSet: rawImportSymbol(c, s) s = nextIter(i, fromMod.tab) @@ -110,22 +110,22 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) = elif exceptSet.isNil or s.name.id notin exceptSet: rawImportSymbol(c, s) of nkExportExceptStmt: - localError(n.info, errGenerated, "'export except' not implemented") + localError(c.config, n.info, "'export except' not implemented") else: for i in 0..safeLen(n)-1: importForwarded(c, n.sons[i], exceptSet) -proc importModuleAs(n: PNode, realModule: PSym): PSym = +proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym = result = realModule if n.kind != nkImportAs: discard elif n.len != 2 or n.sons[1].kind != nkIdent: - localError(n.info, errGenerated, "module alias must be an identifier") + localError(c.config, n.info, "module alias must be an identifier") elif n.sons[1].ident.id != realModule.name.id: # some misguided guy will write 'import abc.foo as foo' ... result = createModuleAlias(realModule, n.sons[1].ident, realModule.info) proc myImportModule(c: PContext, n: PNode): PSym = - var f = checkModuleName(n) + var f = checkModuleName(c.config, n) if f != InvalidFileIDX: let L = c.graph.importStack.len let recursion = c.graph.importStack.find(f) @@ -138,7 +138,7 @@ proc myImportModule(c: PContext, n: PNode): PSym = err.add toFullPath(c.graph.importStack[i]) & " imports " & toFullPath(c.graph.importStack[i+1]) c.recursiveDep = err - result = importModuleAs(n, gImportModule(c.graph, c.module, f, c.cache)) + result = importModuleAs(c, n, gImportModule(c.graph, c.module, f, c.cache)) #echo "set back to ", L c.graph.importStack.setLen(L) # we cannot perform this check reliably because of @@ -146,12 +146,12 @@ proc myImportModule(c: PContext, n: PNode): PSym = when true: if result.info.fileIndex == c.module.info.fileIndex and result.info.fileIndex == n.info.fileIndex: - localError(n.info, errGenerated, "A module cannot import itself") + localError(c.config, n.info, "A module cannot import itself") if sfDeprecated in result.flags: if result.constraint != nil: - message(n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s) + message(c.config, n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s) else: - message(n.info, warnDeprecated, result.name.s) + message(c.config, n.info, warnDeprecated, result.name.s) suggestSym(n.info, result, c.graph.usageSym, false) proc impMod(c: PContext; it: PNode) = @@ -182,7 +182,7 @@ proc evalImport(c: PContext, n: PNode): PNode = proc evalFrom(c: PContext, n: PNode): PNode = result = n - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) var m = myImportModule(c, n.sons[0]) if m != nil: n.sons[0] = newSymNode(m) @@ -193,14 +193,14 @@ proc evalFrom(c: PContext, n: PNode): PNode = proc evalImportExcept*(c: PContext, n: PNode): PNode = result = n - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) var m = myImportModule(c, n.sons[0]) if m != nil: n.sons[0] = newSymNode(m) addDecl(c, m, n.info) # add symbol to symbol table of module var exceptSet = initIntSet() for i in countup(1, sonsLen(n) - 1): - let ident = lookups.considerQuotedIdent(n.sons[i]) + let ident = lookups.considerQuotedIdent(c.config, n.sons[i]) exceptSet.incl(ident.id) importAllSymbolsExcept(c, m, exceptSet) #importForwarded(c, m.ast, exceptSet) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 5aa9037719..31d3f75a36 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -12,7 +12,7 @@ import os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer, wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees, - rodread, types, lookups + rodread, types, lookups, configuration const FirstCallConv* = wNimcall @@ -84,8 +84,12 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode = proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) # implementation -proc invalidPragma*(n: PNode) = - localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments})) +const + errStringLiteralExpected = "string literal expected" + errIntLiteralExpected = "integer literal expected" + +proc invalidPragma*(c: PContext; n: PNode) = + localError(c.config, n.info, "invalid pragma: " % renderTree(n, {renderNoComments})) proc pragmaAsm*(c: PContext, n: PNode): char = result = '\0' @@ -96,12 +100,12 @@ proc pragmaAsm*(c: PContext, n: PNode): char = case whichKeyword(it.sons[0].ident) of wSubsChar: if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal)) - else: invalidPragma(it) - else: invalidPragma(it) + else: invalidPragma(c, it) + else: invalidPragma(c, it) else: - invalidPragma(it) + invalidPragma(c, it) -proc setExternName(s: PSym, extname: string, info: TLineInfo) = +proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) = # special cases to improve performance: if extname == "$1": s.loc.r = rope(s.name.s) @@ -111,28 +115,28 @@ proc setExternName(s: PSym, extname: string, info: TLineInfo) = try: s.loc.r = rope(extname % s.name.s) except ValueError: - localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)") + localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)") if gCmd == cmdPretty and '$' notin extname: # note that '{.importc.}' is transformed into '{.importc: "$1".}' s.loc.flags.incl(lfFullExternalName) -proc makeExternImport(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc makeExternImport(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfImportc) excl(s.flags, sfForward) -proc makeExternExport(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc makeExternExport(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfExportc) -proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc processImportCompilerProc(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfImportc) excl(s.flags, sfForward) incl(s.loc.flags, lfImportCompilerProc) -proc processImportCpp(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfImportc) incl(s.flags, sfInfixCall) excl(s.flags, sfForward) @@ -141,43 +145,43 @@ proc processImportCpp(s: PSym, extname: string, info: TLineInfo) = incl(m.flags, sfCompileToCpp) extccomp.gMixedMode = true -proc processImportObjC(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfImportc) incl(s.flags, sfNamedParamCall) excl(s.flags, sfForward) let m = s.getModule() incl(m.flags, sfCompileToObjC) -proc newEmptyStrNode(n: PNode): PNode {.noinline.} = - result = newNodeIT(nkStrLit, n.info, getSysType(tyString)) +proc newEmptyStrNode(c: PContext; n: PNode): PNode {.noinline.} = + result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString)) result.strVal = "" proc getStrLitNode(c: PContext, n: PNode): PNode = if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) # error correction: - result = newEmptyStrNode(n) + result = newEmptyStrNode(c, n) else: n.sons[1] = c.semConstExpr(c, n.sons[1]) case n.sons[1].kind of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1] else: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) # error correction: - result = newEmptyStrNode(n) + result = newEmptyStrNode(c, n) proc expectStrLit(c: PContext, n: PNode): string = result = getStrLitNode(c, n).strVal proc expectIntLit(c: PContext, n: PNode): int = if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errIntLiteralExpected) + localError(c.config, n.info, errIntLiteralExpected) else: n.sons[1] = c.semConstExpr(c, n.sons[1]) case n.sons[1].kind of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal) - else: localError(n.info, errIntLiteralExpected) + else: localError(c.config, n.info, errIntLiteralExpected) proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string = if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n) @@ -190,7 +194,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) = #if sfSystemModule notin c.module.flags: # liMessage(n.info, errMagicOnlyInSystem) if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) return var v: string if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s @@ -199,7 +203,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) = if substr($m, 1) == v: s.magic = m break - if s.magic == mNone: message(n.info, warnUnknownMagic, v) + if s.magic == mNone: message(c.config, n.info, warnUnknownMagic, v) proc wordToCallConv(sw: TSpecialWord): TCallingConvention = # this assumes that the order of special words and calling conventions is @@ -211,7 +215,7 @@ proc isTurnedOn(c: PContext, n: PNode): bool = let x = c.semConstBoolExpr(c, n.sons[1]) n.sons[1] = x if x.kind == nkIntLit: return x.intVal != 0 - localError(n.info, errOnOrOffExpected) + localError(c.config, n.info, "'on' or 'off' expected") proc onOff(c: PContext, n: PNode, op: TOptions) = if isTurnedOn(c, n): gOptions = gOptions + op @@ -227,9 +231,9 @@ proc processCallConv(c: PContext, n: PNode) = case sw of FirstCallConv..LastCallConv: c.optionStack[^1].defaultCC = wordToCallConv(sw) - else: localError(n.info, errCallConvExpected) + else: localError(c.config, n.info, "calling convention expected") else: - localError(n.info, errCallConvExpected) + localError(c.config, n.info, "calling convention expected") proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib = for it in c.libs: @@ -240,13 +244,13 @@ proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib = result.path = path c.libs.add result if path.kind in {nkStrLit..nkTripleStrLit}: - result.isOverriden = options.isDynlibOverride(path.strVal) + result.isOverriden = options.isDynlibOverride(c.config, path.strVal) proc expectDynlibNode(c: PContext, n: PNode): PNode = if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) # error correction: - result = newEmptyStrNode(n) + result = newEmptyStrNode(c, n) else: # For the OpenGL wrapper we support: # {.dynlib: myGetProcAddr(...).} @@ -254,8 +258,8 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode = if result.kind == nkSym and result.sym.kind == skConst: result = result.sym.ast # look it up if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}: - localError(n.info, errStringLiteralExpected) - result = newEmptyStrNode(n) + localError(c.config, n.info, errStringLiteralExpected) + result = newEmptyStrNode(c, n) proc processDynLib(c: PContext, n: PNode, sym: PSym) = if (sym == nil) or (sym.kind == skModule): @@ -278,39 +282,37 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = sym.typ.callConv = ccCDecl proc processNote(c: PContext, n: PNode) = - if (n.kind in nkPragmaCallKinds) and (sonsLen(n) == 2) and - (n.sons[0].kind == nkBracketExpr) and - (n.sons[0].sons.len == 2) and - (n.sons[0].sons[1].kind == nkIdent) and - (n.sons[0].sons[0].kind == nkIdent): - #and (n.sons[1].kind == nkIdent): + if n.kind in nkPragmaCallKinds and len(n) == 2 and + n[0].kind == nkBracketExpr and + n[0].len == 2 and + n[0][1].kind == nkIdent and n[0][0].kind == nkIdent: var nk: TNoteKind - case whichKeyword(n.sons[0].sons[0].ident) + case whichKeyword(n[0][0].ident) of wHint: - var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s) + var x = findStr(HintsToStr, n[0][1].ident.s) if x >= 0: nk = TNoteKind(x + ord(hintMin)) - else: invalidPragma(n); return + else: invalidPragma(c, n); return of wWarning: - var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s) + var x = findStr(WarningsToStr, n[0][1].ident.s) if x >= 0: nk = TNoteKind(x + ord(warnMin)) - else: invalidPragma(n); return + else: invalidPragma(c, n); return else: - invalidPragma(n) + invalidPragma(c, n) return - let x = c.semConstBoolExpr(c, n.sons[1]) + let x = c.semConstBoolExpr(c, n[1]) n.sons[1] = x - if x.kind == nkIntLit and x.intVal != 0: incl(gNotes, nk) - else: excl(gNotes, nk) + if x.kind == nkIntLit and x.intVal != 0: incl(c.config.notes, nk) + else: excl(c.config.notes, nk) else: - invalidPragma(n) + invalidPragma(c, n) proc processOption(c: PContext, n: PNode): bool = if n.kind notin nkPragmaCallKinds or n.len != 2: result = true elif n.sons[0].kind == nkBracketExpr: processNote(c, n) elif n.sons[0].kind != nkIdent: result = true else: - var sw = whichKeyword(n.sons[0].ident) + let sw = whichKeyword(n.sons[0].ident) case sw of wChecks: onOff(c, n, ChecksOptions) of wObjChecks: onOff(c, n, {optObjCheck}) @@ -337,7 +339,7 @@ proc processOption(c: PContext, n: PNode): bool = of wDynlib: processDynLib(c, n, nil) of wOptimization: if n.sons[1].kind != nkIdent: - invalidPragma(n) + invalidPragma(c, n) else: case n.sons[1].ident.s.normalize of "speed": @@ -349,20 +351,20 @@ proc processOption(c: PContext, n: PNode): bool = of "none": excl(gOptions, optOptimizeSpeed) excl(gOptions, optOptimizeSize) - else: localError(n.info, errNoneSpeedOrSizeExpected) + else: localError(c.config, n.info, "'none', 'speed' or 'size' expected") of wImplicitStatic: onOff(c, n, {optImplicitStatic}) of wPatterns: onOff(c, n, {optPatterns}) else: result = true proc processPush(c: PContext, n: PNode, start: int) = if n.sons[start-1].kind in nkPragmaCallKinds: - localError(n.info, errGenerated, "'push' can't have arguments") - var x = newOptionEntry() + localError(c.config, n.info, "'push' cannot have arguments") + var x = newOptionEntry(c.config) var y = c.optionStack[^1] x.options = gOptions x.defaultCC = y.defaultCC x.dynlib = y.dynlib - x.notes = gNotes + x.notes = c.config.notes c.optionStack.add(x) for i in countup(start, sonsLen(n) - 1): if processOption(c, n.sons[i]): @@ -370,29 +372,29 @@ proc processPush(c: PContext, n: PNode, start: int) = if x.otherPragmas.isNil: x.otherPragmas = newNodeI(nkPragma, n.info) x.otherPragmas.add n.sons[i] - #localError(n.info, errOptionExpected) + #localError(c.config, n.info, errOptionExpected) proc processPop(c: PContext, n: PNode) = if c.optionStack.len <= 1: - localError(n.info, errAtPopWithoutPush) + localError(c.config, n.info, "{.pop.} without a corresponding {.push.}") else: gOptions = c.optionStack[^1].options - gNotes = c.optionStack[^1].notes + c.config.notes = c.optionStack[^1].notes c.optionStack.setLen(c.optionStack.len - 1) proc processDefine(c: PContext, n: PNode) = - if (n.kind in nkPragmaCallKinds and n.len == 2) and (n.sons[1].kind == nkIdent): - defineSymbol(n.sons[1].ident.s) - message(n.info, warnDeprecated, "define") + if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent): + defineSymbol(c.config.symbols, n[1].ident.s) + message(c.config, n.info, warnDeprecated, "define") else: - invalidPragma(n) + invalidPragma(c, n) proc processUndef(c: PContext, n: PNode) = - if (n.kind in nkPragmaCallKinds and n.len == 2) and (n.sons[1].kind == nkIdent): - undefSymbol(n.sons[1].ident.s) - message(n.info, warnDeprecated, "undef") + if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent): + undefSymbol(c.config.symbols, n[1].ident.s) + message(c.config, n.info, warnDeprecated, "undef") else: - invalidPragma(n) + invalidPragma(c, n) type TLinkFeature = enum @@ -406,18 +408,18 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string = if not fileExists(result): if isAbsolute(s): result = s else: - result = findFile(s) + result = findFile(c.config, s) if result.len == 0: result = s proc processCompile(c: PContext, n: PNode) = proc getStrLit(c: PContext, n: PNode; i: int): string = - n.sons[i] = c.semConstExpr(c, n.sons[i]) - case n.sons[i].kind + n.sons[i] = c.semConstExpr(c, n[i]) + case n[i].kind of nkStrLit, nkRStrLit, nkTripleStrLit: - shallowCopy(result, n.sons[i].strVal) + shallowCopy(result, n[i].strVal) else: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) result = "" let it = if n.kind in nkPragmaCallKinds and n.len == 2: n.sons[1] else: n @@ -428,26 +430,27 @@ proc processCompile(c: PContext, n: PNode) = for f in os.walkFiles(found): let nameOnly = extractFilename(f) var cf = Cfile(cname: f, - obj: completeCFilePath(dest % nameOnly), + obj: completeCFilePath(c.config, dest % nameOnly), flags: {CfileFlag.External}) - extccomp.addExternalFileToCompile(cf) + extccomp.addExternalFileToCompile(c.config, cf) else: let s = expectStrLit(c, n) var found = parentDir(n.info.toFullPath) / s if not fileExists(found): if isAbsolute(s): found = s else: - found = findFile(s) + found = findFile(c.config, s) if found.len == 0: found = s - extccomp.addExternalFileToCompile(found) + extccomp.addExternalFileToCompile(c.config, found) proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = let found = relativeFile(c, n, CC[cCompiler].objExt) case feature - of linkNormal: extccomp.addExternalFileToLink(found) + of linkNormal: extccomp.addExternalFileToLink(c.config, found) of linkSys: - extccomp.addExternalFileToLink(libpath / completeCFilePath(found, false)) - else: internalError(n.info, "processCommonLink") + extccomp.addExternalFileToLink(c.config, + c.config.libpath / completeCFilePath(c.config, found, false)) + else: internalError(c.config, n.info, "processCommonLink") proc pragmaBreakpoint(c: PContext, n: PNode) = discard getOptionalStr(c, n, "") @@ -456,7 +459,7 @@ proc pragmaWatchpoint(c: PContext, n: PNode) = if n.kind in nkPragmaCallKinds and n.len == 2: n.sons[1] = c.semExpr(c, n.sons[1]) else: - invalidPragma(n) + invalidPragma(c, n) proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = case n.sons[1].kind @@ -464,7 +467,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info) var str = n.sons[1].strVal if str == "": - localError(n.info, errEmptyAsm) + localError(con.config, n.info, "empty 'asm' statement") return # now parse the string literal and substitute symbols: var a = 0 @@ -490,12 +493,12 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = if c < 0: break a = c + 1 else: - illFormedAstLocal(n) + illFormedAstLocal(n, con.config) result = newNode(nkAsmStmt, n.info) proc pragmaEmit(c: PContext, n: PNode) = if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) else: let n1 = n[1] if n1.kind == nkBracket: @@ -509,20 +512,20 @@ proc pragmaEmit(c: PContext, n: PNode) = of nkStrLit, nkRStrLit, nkTripleStrLit: n.sons[1] = semAsmOrEmit(c, n, '`') else: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) -proc noVal(n: PNode) = - if n.kind in nkPragmaCallKinds and n.len > 1: invalidPragma(n) +proc noVal(c: PContext; n: PNode) = + if n.kind in nkPragmaCallKinds and n.len > 1: invalidPragma(c, n) proc pragmaUnroll(c: PContext, n: PNode) = if c.p.nestedLoopCounter <= 0: - invalidPragma(n) + invalidPragma(c, n) elif n.kind in nkPragmaCallKinds and n.len == 2: var unrollFactor = expectIntLit(c, n) if unrollFactor <% 32: n.sons[1] = newIntNode(nkIntLit, unrollFactor) else: - invalidPragma(n) + invalidPragma(c, n) proc pragmaLine(c: PContext, n: PNode) = if n.kind in nkPragmaCallKinds and n.len == 2: @@ -535,24 +538,24 @@ proc pragmaLine(c: PContext, n: PNode) = if x.kind == nkExprColonExpr: x = x.sons[1] if y.kind == nkExprColonExpr: y = y.sons[1] if x.kind != nkStrLit: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) elif y.kind != nkIntLit: - localError(n.info, errIntLiteralExpected) + localError(c.config, n.info, errIntLiteralExpected) else: # XXX this produces weird paths which are not properly resolved: - n.info.fileIndex = msgs.fileInfoIdx(x.strVal) + n.info.fileIndex = msgs.fileInfoIdx(c.config, x.strVal) n.info.line = uint16(y.intVal) else: - localError(n.info, errXExpected, "tuple") + localError(c.config, n.info, "tuple expected") else: # sensible default: n.info = getInfoContext(-1) proc processPragma(c: PContext, n: PNode, i: int) = let it = n[i] - if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(n) - elif it[0].kind != nkIdent: invalidPragma(n) - elif it[1].kind != nkIdent: invalidPragma(n) + if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(c, n) + elif it[0].kind != nkIdent: invalidPragma(c, n) + elif it[1].kind != nkIdent: invalidPragma(c, n) var userPragma = newSym(skTemplate, it[1].ident, nil, it.info) userPragma.ast = newNode(nkPragma, n.info, n.sons[i+1..^1]) @@ -562,7 +565,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) = proc processExc(c: PContext, x: PNode) = var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs) if t.kind != tyObject: - localError(x.info, errGenerated, "invalid type for raises/tags list") + localError(c.config, x.info, errGenerated, "invalid type for raises/tags list") x.typ = t if n.kind in nkPragmaCallKinds and n.len == 2: @@ -572,51 +575,51 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) = else: for e in items(it): processExc(c, e) else: - invalidPragma(n) + invalidPragma(c, n) proc pragmaLockStmt(c: PContext; it: PNode) = if it.kind notin nkPragmaCallKinds or it.len != 2: - invalidPragma(it) + invalidPragma(c, it) else: let n = it[1] if n.kind != nkBracket: - localError(n.info, errGenerated, "locks pragma takes a list of expressions") + localError(c.config, 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 notin nkPragmaCallKinds or it.len != 2: - invalidPragma(it) + invalidPragma(c, it) else: case it[1].kind of nkStrLit, nkRStrLit, nkTripleStrLit: if it[1].strVal == "unknown": result = UnknownLockLevel else: - localError(it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")") + localError(c.config, it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")") else: let x = expectIntLit(c, it) if x < 0 or x > MaxLockLevel: - localError(it[1].info, "integer must be within 0.." & $MaxLockLevel) + localError(c.config, it[1].info, "integer must be within 0.." & $MaxLockLevel) else: result = TLockLevel(x) -proc typeBorrow(sym: PSym, n: PNode) = +proc typeBorrow(c: PContext; sym: PSym, n: PNode) = if n.kind in nkPragmaCallKinds and n.len == 2: let it = n.sons[1] if it.kind != nkAccQuoted: - localError(n.info, "a type can only borrow `.` for now") + localError(c.config, n.info, "a type can only borrow `.` for now") incl(sym.typ.flags, tfBorrowDot) -proc markCompilerProc(s: PSym) = +proc markCompilerProc(c: PContext; s: PSym) = # minor hack ahead: FlowVar is the only generic .compilerProc type which # should not have an external name set: if s.kind != skType or s.name.s != "FlowVar": - makeExternExport(s, "$1", s.info) + makeExternExport(c, s, "$1", s.info) incl(s.flags, sfCompilerProc) incl(s.flags, sfUsed) - registerCompilerProc(s) + registerCompilerProc(c.graph, s) proc deprecatedStmt(c: PContext; outerPragma: PNode) = let pragma = outerPragma[1] @@ -625,24 +628,24 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) = c.module.constraint = getStrLitNode(c, outerPragma) return if pragma.kind != nkBracket: - localError(pragma.info, "list of key:value pairs expected"); return + localError(c.config, pragma.info, "list of key:value pairs expected"); return for n in pragma: if n.kind in nkPragmaCallKinds and n.len == 2: let dest = qualifiedLookUp(c, n[1], {checkUndeclared}) if dest == nil or dest.kind in routineKinds: - localError(n.info, warnUser, "the .deprecated pragma is unreliable for routines") - let src = considerQuotedIdent(n[0]) + localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines") + let src = considerQuotedIdent(c.config, n[0]) let alias = newSym(skAlias, src, dest, n[0].info) incl(alias.flags, sfExported) - if sfCompilerProc in dest.flags: markCompilerProc(alias) + if sfCompilerProc in dest.flags: markCompilerProc(c, alias) addInterfaceDecl(c, alias) n.sons[1] = newSymNode(dest) else: - localError(n.info, "key:value pair expected") + localError(c.config, n.info, "key:value pair expected") proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym = if it.kind notin nkPragmaCallKinds or it.len != 2: - invalidPragma(it); return + invalidPragma(c, it); return let n = it[1] if n.kind == nkSym: result = n.sym @@ -654,7 +657,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym = # We return a dummy symbol; later passes over the type will repair it. # Generic instantiation needs to know about this too. But we're lazy # and perform the lookup on demand instead. - result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info) + result = newSym(skUnknown, considerQuotedIdent(c.config, n), nil, n.info) else: result = qualifiedLookUp(c, n, {checkUndeclared}) @@ -667,12 +670,12 @@ proc semCustomPragma(c: PContext, n: PNode): PNode = elif n.kind in nkPragmaCallKinds + {nkIdent}: result = n else: - invalidPragma(n) + invalidPragma(c, n) return n let r = c.semOverloadedCall(c, result, n, {skTemplate}, {}) if r.isNil or sfCustomPragma notin r[0].sym.flags: - invalidPragma(n) + invalidPragma(c, n) else: result = r if n.kind == nkIdent: @@ -682,7 +685,7 @@ proc semCustomPragma(c: PContext, n: PNode): PNode = proc processExperimental(c: PContext; n: PNode; s: PSym) = if not isTopLevel(c): - localError(n.info, "'experimental' pragma only valid as toplevel statement") + localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement") if n.kind notin nkPragmaCallKinds or n.len != 2: c.features.incl oldExperimentalFeatures else: @@ -692,9 +695,9 @@ proc processExperimental(c: PContext; n: PNode; s: PSym) = try: c.features.incl parseEnum[Feature](n[1].strVal) except ValueError: - localError(n[1].info, "unknown experimental feature") + localError(c.config, n[1].info, "unknown experimental feature") else: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, validPragmas: TSpecialWords): bool = @@ -706,13 +709,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, elif key.kind notin nkIdentKinds: n.sons[i] = semCustomPragma(c, it) return - let ident = considerQuotedIdent(key) + let ident = considerQuotedIdent(c.config, key) var userPragma = strTableGet(c.userPragmas, ident) if userPragma != nil: # number of pragmas increase/decrease with user pragma expansion inc c.instCounter if c.instCounter > 100: - globalError(it.info, errRecursiveDependencyX, userPragma.name.s) + globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s) pragma(c, sym, userPragma.ast, validPragmas) n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content @@ -723,78 +726,78 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, if k in validPragmas: case k of wExportc: - makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) + makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info) incl(sym.flags, sfUsed) # avoid wrong hints of wImportc: let name = getOptionalStr(c, it, "$1") - cppDefine(c.graph.config, name) - makeExternImport(sym, name, it.info) + cppDefine(c.config, name) + makeExternImport(c, sym, name, it.info) of wImportCompilerProc: let name = getOptionalStr(c, it, "$1") - cppDefine(c.graph.config, name) - processImportCompilerProc(sym, name, it.info) - of wExtern: setExternName(sym, expectStrLit(c, it), it.info) + cppDefine(c.config, name) + processImportCompilerProc(c, sym, name, it.info) + of wExtern: setExternName(c, sym, expectStrLit(c, it), it.info) of wImmediate: if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate) incl(sym.flags, sfAllUntyped) - message(n.info, warnDeprecated, "use 'untyped' parameters instead; immediate") - else: invalidPragma(it) + message(c.config, n.info, warnDeprecated, "use 'untyped' parameters instead; immediate") + else: invalidPragma(c, it) of wDirty: if sym.kind == skTemplate: incl(sym.flags, sfDirty) - else: invalidPragma(it) + else: invalidPragma(c, it) of wImportCpp: - processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info) + processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info) of wImportObjC: - processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info) + processImportObjC(c, sym, getOptionalStr(c, it, "$1"), it.info) of wAlign: - if sym.typ == nil: invalidPragma(it) + if sym.typ == nil: invalidPragma(c, it) var align = expectIntLit(c, it) if (not isPowerOfTwo(align) and align != 0) or align >% high(int16): - localError(it.info, errPowerOfTwoExpected) + localError(c.config, it.info, "power of two expected") else: sym.typ.align = align.int16 of wSize: - if sym.typ == nil: invalidPragma(it) + if sym.typ == nil: invalidPragma(c, it) var size = expectIntLit(c, it) if not isPowerOfTwo(size) or size <= 0 or size > 8: - localError(it.info, errPowerOfTwoExpected) + localError(c.config, it.info, "power of two expected") else: sym.typ.size = size of wNodecl: - noVal(it) + noVal(c, it) incl(sym.loc.flags, lfNoDecl) of wPure, wAsmNoStackFrame: - noVal(it) + noVal(c, it) if sym != nil: - if k == wPure and sym.kind in routineKinds: invalidPragma(it) + if k == wPure and sym.kind in routineKinds: invalidPragma(c, it) else: incl(sym.flags, sfPure) of wVolatile: - noVal(it) + noVal(c, it) incl(sym.flags, sfVolatile) of wRegister: - noVal(it) + noVal(c, it) incl(sym.flags, sfRegister) of wThreadVar: - noVal(it) + noVal(c, it) incl(sym.flags, sfThread) of wDeadCodeElimUnused: discard # deprecated, dead code elim always on of wNoForward: pragmaNoForward(c, it) of wReorder: pragmaNoForward(c, it, sfReorder) of wMagic: processMagic(c, it, sym) of wCompileTime: - noVal(it) + noVal(c, it) incl(sym.flags, sfCompileTime) incl(sym.loc.flags, lfNoDecl) of wGlobal: - noVal(it) + noVal(c, it) incl(sym.flags, sfGlobal) incl(sym.flags, sfPure) of wMerge: # only supported for backwards compat, doesn't do anything anymore - noVal(it) + noVal(c, it) of wConstructor: - noVal(it) + noVal(c, it) incl(sym.flags, sfConstructor) of wHeader: var lib = getLib(c, libHeader, getStrLitNode(c, it)) @@ -807,25 +810,26 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wOverride: sym.flags.incl sfOverriden of wNosideeffect: - noVal(it) + noVal(c, it) incl(sym.flags, sfNoSideEffect) if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect) of wSideeffect: - noVal(it) + noVal(c, it) incl(sym.flags, sfSideEffect) of wNoreturn: - noVal(it) + noVal(c, it) incl(sym.flags, sfNoReturn) if sym.typ[0] != nil: - localError(sym.ast[paramsPos][0].info, errNoReturnWithReturnTypeNotAllowed) + localError(c.config, sym.ast[paramsPos][0].info, + ".noreturn with return type not allowed") of wDynlib: processDynLib(c, it, sym) of wCompilerProc, wCore: - noVal(it) # compilerproc may not get a string! + noVal(c, it) # compilerproc may not get a string! cppDefine(c.graph.config, sym.name.s) - if sfFromGeneric notin sym.flags: markCompilerProc(sym) + if sfFromGeneric notin sym.flags: markCompilerProc(c, sym) of wProcVar: - noVal(it) + noVal(c, it) incl(sym.flags, sfProcvar) of wExplain: sym.flags.incl sfExplain @@ -837,74 +841,74 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, elif sym != nil: incl(sym.flags, sfDeprecated) else: incl(c.module.flags, sfDeprecated) of wVarargs: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfVarargs) of wBorrow: if sym.kind == skType: - typeBorrow(sym, it) + typeBorrow(c, sym, it) else: - noVal(it) + noVal(c, it) incl(sym.flags, sfBorrow) of wFinal: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfFinal) of wInheritable: - noVal(it) - if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it) + noVal(c, it) + if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(c, it) else: incl(sym.typ.flags, tfInheritable) of wPackage: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.flags, sfForward) of wAcyclic: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfAcyclic) of wShallow: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfShallow) of wThread: - noVal(it) + noVal(c, it) incl(sym.flags, sfThread) incl(sym.flags, sfProcvar) if sym.typ != nil: incl(sym.typ.flags, tfThread) if sym.typ.callConv == ccClosure: sym.typ.callConv = ccDefault of wGcSafe: - noVal(it) + noVal(c, it) if sym != nil: if sym.kind != skType: incl(sym.flags, sfThread) if sym.typ != nil: incl(sym.typ.flags, tfGcSafe) - else: invalidPragma(it) + else: invalidPragma(c, it) else: discard "no checking if used as a code block" of wPacked: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfPacked) - of wHint: message(it.info, hintUser, expectStrLit(c, it)) - of wWarning: message(it.info, warnUser, expectStrLit(c, it)) + of wHint: message(c.config, it.info, hintUser, expectStrLit(c, it)) + of wWarning: message(c.config, it.info, warnUser, expectStrLit(c, it)) of wError: if sym != nil and sym.isRoutine: # This is subtle but correct: the error *statement* is only # allowed for top level statements. Seems to be easier than # distinguishing properly between # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}`` - noVal(it) + noVal(c, it) incl(sym.flags, sfError) else: - localError(it.info, errUser, expectStrLit(c, it)) - of wFatal: fatal(it.info, errUser, expectStrLit(c, it)) + localError(c.config, it.info, errUser, expectStrLit(c, it)) + of wFatal: fatal(c.config, it.info, errUser, expectStrLit(c, it)) of wDefine: processDefine(c, it) of wUndef: processUndef(c, it) of wCompile: processCompile(c, it) of wLink: processCommonLink(c, it, linkNormal) of wLinksys: processCommonLink(c, it, linkSys) - of wPassl: extccomp.addLinkOption(expectStrLit(c, it)) - of wPassc: extccomp.addCompileOption(expectStrLit(c, it)) + of wPassl: extccomp.addLinkOption(c.config, expectStrLit(c, it)) + of wPassc: extccomp.addCompileOption(c.config, expectStrLit(c, it)) of wBreakpoint: pragmaBreakpoint(c, it) of wWatchPoint: pragmaWatchpoint(c, it) of wPush: @@ -918,10 +922,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, processPragma(c, n, i) result = true of wDiscardable: - noVal(it) + noVal(c, it) if sym != nil: incl(sym.flags, sfDiscardable) of wNoInit: - noVal(it) + noVal(c, it) if sym != nil: incl(sym.flags, sfNoInit) of wCodegenDecl: processCodegenDecl(c, it, sym) of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, @@ -932,106 +936,106 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, wPatterns: if processOption(c, it): # calling conventions (boring...): - localError(it.info, errOptionExpected) + localError(c.config, it.info, "option expected") of FirstCallConv..LastCallConv: assert(sym != nil) - if sym.typ == nil: invalidPragma(it) + if sym.typ == nil: invalidPragma(c, it) else: sym.typ.callConv = wordToCallConv(k) of wEmit: pragmaEmit(c, it) of wUnroll: pragmaUnroll(c, it) - of wLinearScanEnd, wComputedGoto: noVal(it) + of wLinearScanEnd, wComputedGoto: noVal(c, it) of wEffects: # is later processed in effect analysis: - noVal(it) + noVal(c, it) of wIncompleteStruct: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfIncompleteStruct) of wUnchecked: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfUncheckedArray) of wUnion: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfUnion) of wRequiresInit: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfNeedsInit) of wByRef: - noVal(it) + noVal(c, it) if sym == nil or sym.typ == nil: - if processOption(c, it): localError(it.info, errOptionExpected) + if processOption(c, it): localError(c.config, it.info, "option expected") else: incl(sym.typ.flags, tfByRef) of wByCopy: - noVal(it) - if sym.kind != skType or sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.kind != skType or sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfByCopy) of wPartial: - noVal(it) - if sym.kind != skType or sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.kind != skType or sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfPartial) of wInject, wGensym: # We check for errors, but do nothing with these pragmas otherwise # as they are handled directly in 'evalTemplate'. - noVal(it) - if sym == nil: invalidPragma(it) + noVal(c, it) + if sym == nil: invalidPragma(c, 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) + elif sym.typ == nil: invalidPragma(c, it) else: sym.typ.lockLevel = pragmaLocks(c, it) of wBitsize: if sym == nil or sym.kind != skField: - invalidPragma(it) + invalidPragma(c, it) else: sym.bitsize = expectIntLit(c, it) of wGuard: if sym == nil or sym.kind notin {skVar, skLet, skField}: - invalidPragma(it) + invalidPragma(c, it) else: sym.guard = pragmaGuard(c, it, sym.kind) of wGoto: if sym == nil or sym.kind notin {skVar, skLet}: - invalidPragma(it) + invalidPragma(c, it) else: sym.flags.incl sfGoto of wExportNims: - if sym == nil: invalidPragma(it) - else: magicsys.registerNimScriptSymbol(sym) + if sym == nil: invalidPragma(c, it) + else: magicsys.registerNimScriptSymbol(c.graph, sym) of wInjectStmt: if it.kind notin nkPragmaCallKinds or it.len != 2: - localError(it.info, errExprExpected) + localError(c.config, it.info, "expression expected") else: it.sons[1] = c.semExpr(c, it.sons[1]) of wExperimental: processExperimental(c, it, sym) of wThis: if it.kind in nkPragmaCallKinds and it.len == 2: - c.selfName = considerQuotedIdent(it[1]) + c.selfName = considerQuotedIdent(c.config, it[1]) elif it.kind == nkIdent or it.len == 1: c.selfName = getIdent("self") else: - localError(it.info, "'this' pragma is allowed to have zero or one arguments") + localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments") of wNoRewrite: - noVal(it) + noVal(c, it) of wBase: - noVal(it) + noVal(c, it) sym.flags.incl sfBase of wIntDefine: sym.magic = mIntDefine of wStrDefine: sym.magic = mStrDefine of wUsed: - noVal(it) - if sym == nil: invalidPragma(it) + noVal(c, it) + if sym == nil: invalidPragma(c, it) else: sym.flags.incl sfUsed of wLiftLocals: discard - else: invalidPragma(it) + else: invalidPragma(c, it) else: n.sons[i] = semCustomPragma(c, it) @@ -1046,12 +1050,12 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, var i = 0 while i < o.len(): if singlePragma(c, sym, o, i, validPragmas): - internalError(n.info, "implicitPragmas") + internalError(c.config, n.info, "implicitPragmas") inc i popInfoContext() if lfExportLib in sym.loc.flags and sfExportc notin sym.flags: - localError(n.info, errDynlibRequiresExportc) + localError(c.config, n.info, ".dynlib requires .exportc") var lib = c.optionStack[^1].dynlib if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and sfImportc in sym.flags and lib != nil: @@ -1063,7 +1067,7 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool = if n == nil or n.sons == nil: return false - for p in n.sons: + for p in n: var key = if p.kind in nkPragmaCallKinds and p.len > 1: p[0] else: p if key.kind == nkIdent and whichKeyword(key.ident) == pragma: return true diff --git a/compiler/procfind.nim b/compiler/procfind.nim index f7d86aaef0..042947e72f 100644 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -14,14 +14,12 @@ import ast, astalgo, msgs, semdata, types, trees, strutils proc equalGenericParams(procA, procB: PNode): bool = - if sonsLen(procA) != sonsLen(procB): return + if sonsLen(procA) != sonsLen(procB): return false for i in countup(0, sonsLen(procA) - 1): if procA.sons[i].kind != nkSym: - internalError(procA.info, "equalGenericParams") - return + return false if procB.sons[i].kind != nkSym: - internalError(procB.info, "equalGenericParams") - return + return false let a = procA.sons[i].sym let b = procB.sons[i].sym if a.name.id != b.name.id or @@ -57,7 +55,7 @@ proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym = of paramsEqual: return of paramsIncompatible: - localError(fn.info, errNotOverloadable, fn.name.s) + localError(c.config, fn.info, "overloaded '$1' leads to ambiguous calls" % fn.name.s) return of paramsNotEqual: discard @@ -76,10 +74,10 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym = let message = ("public implementation '$1' has non-public " & "forward declaration in $2") % [getProcHeader(result), $result.info] - localError(fn.info, errGenerated, message) + localError(c.config, fn.info, message) return of paramsIncompatible: - localError(fn.info, errNotOverloadable, fn.name.s) + localError(c.config, fn.info, "overloaded '$1' leads to ambiguous calls" % fn.name.s) return of paramsNotEqual: discard From 1310279691c82a38ccbd5f6d8616619c0ce006c4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 08:30:55 +0200 Subject: [PATCH 185/214] lambda lifting compiles again --- compiler/dfa.nim | 4 +- compiler/lambdalifting.nim | 175 +++++++++++++++++++------------------ compiler/lowerings.nim | 124 +++++++++++++------------- 3 files changed, 154 insertions(+), 149 deletions(-) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index bc9d13870a..0784151af8 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -102,14 +102,14 @@ proc genLabel(c: Con): TPosition = proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) = let dist = p.int - c.code.len - internalAssert(-0x7fff < dist and dist < 0x7fff) + doAssert(-0x7fff < dist and dist < 0x7fff) c.code.add Instr(n: n, kind: goto, dest: dist) proc patch(c: var Con, p: TPosition) = # patch with current index let p = p.int let diff = c.code.len - p - internalAssert(-0x7fff < diff and diff < 0x7fff) + doAssert(-0x7fff < diff and diff < 0x7fff) c.code[p].dest = diff proc popBlock(c: var Con; oldLen: int) = diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 7757484250..2410f1d368 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -11,7 +11,8 @@ import intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, - idents, renderer, types, magicsys, rodread, lowerings, tables + idents, renderer, types, magicsys, rodread, lowerings, tables, + modulegraphs discard """ The basic approach is that captured vars need to be put on the heap and @@ -125,25 +126,25 @@ proc newCall(a: PSym, b: PNode): PNode = result.add newSymNode(a) result.add b -proc createStateType(iter: PSym): PType = +proc createStateType(g: ModuleGraph; iter: PSym): PType = var n = newNodeI(nkRange, iter.info) addSon(n, newIntNode(nkIntLit, -1)) addSon(n, newIntNode(nkIntLit, 0)) result = newType(tyRange, iter) result.n = n - var intType = nilOrSysInt() + var intType = nilOrSysInt(g) if intType.isNil: intType = newType(tyInt, iter) rawAddSon(result, intType) -proc createStateField(iter: PSym): PSym = +proc createStateField(g: ModuleGraph; iter: PSym): PSym = result = newSym(skField, getIdent(":state"), iter, iter.info) - result.typ = createStateType(iter) + result.typ = createStateType(g, iter) -proc createEnvObj(owner: PSym; info: TLineInfo): PType = +proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType = # YYY meh, just add the state field for every closure for now, it's too # hard to figure out if it comes from a closure iterator: - result = createObj(owner, info, final=false) - rawAddField(result, createStateField(owner)) + result = createObj(g, owner, info, final=false) + rawAddField(result, createStateField(g, owner)) proc getIterResult(iter: PSym): PSym = if resultPos < iter.ast.len: @@ -166,7 +167,7 @@ proc addHiddenParam(routine: PSym, param: PSym) = assert sfFromGeneric in param.flags #echo "produced environment: ", param.id, " for ", routine.id -proc getHiddenParam(routine: PSym): PSym = +proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym = let params = routine.ast.sons[paramsPos] let hidden = lastSon(params) if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName: @@ -174,7 +175,7 @@ proc getHiddenParam(routine: PSym): PSym = assert sfFromGeneric in result.flags else: # writeStackTrace() - localError(routine.info, "internal error: could not find env param for " & routine.name.s) + localError(g.config, routine.info, "internal error: could not find env param for " & routine.name.s) result = routine proc getEnvParam*(routine: PSym): PSym = @@ -208,14 +209,14 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode = result.sons[0] = le result.sons[1] = ri -proc makeClosure*(prc: PSym; env: PNode; info: TLineInfo): PNode = +proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode = result = newNodeIT(nkClosure, info, prc.typ) result.add(newSymNode(prc)) if env == nil: - result.add(newNodeIT(nkNilLit, info, getSysType(tyNil))) + result.add(newNodeIT(nkNilLit, info, getSysType(g, info, tyNil))) else: if env.skipConv.kind == nkClosure: - localError(info, "internal error: taking closure of closure") + localError(g.config, info, "internal error: taking closure of closure") result.add(env) proc interestingIterVar(s: PSym): bool {.inline.} = @@ -232,7 +233,7 @@ proc liftingHarmful(owner: PSym): bool {.inline.} = let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro result = gCmd == cmdCompileToJS and not isCompileTime -proc liftIterSym*(n: PNode; owner: PSym): PNode = +proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) if liftingHarmful(owner): return n let iter = n.sym @@ -240,10 +241,10 @@ proc liftIterSym*(n: PNode; owner: PSym): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) - let hp = getHiddenParam(iter) + let hp = getHiddenParam(g, iter) var env: PNode if owner.isIterator: - let it = getHiddenParam(owner) + let it = getHiddenParam(g, owner) addUniqueField(it.typ.sons[0], hp) env = indirectAccess(newSymNode(it), hp, hp.info) else: @@ -255,11 +256,11 @@ proc liftIterSym*(n: PNode; owner: PSym): PNode = addVar(v, env) result.add(v) # add 'new' statement: - result.add newCall(getSysSym"internalNew", env) - result.add makeClosure(iter, env, n.info) + result.add newCall(getSysSym(g, n.info, "internalNew"), env) + result.add makeClosure(g, iter, env, n.info) -proc freshVarForClosureIter*(s, owner: PSym): PNode = - let envParam = getHiddenParam(owner) +proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode = + let envParam = getHiddenParam(g, owner) let obj = envParam.typ.lastSon addField(obj, s) @@ -269,18 +270,18 @@ proc freshVarForClosureIter*(s, owner: PSym): PNode = if field != nil: result = rawIndirectAccess(access, field, s.info) else: - localError(s.info, "internal error: cannot generate fresh variable") + localError(g.config, s.info, "internal error: cannot generate fresh variable") result = access # ------------------ new stuff ------------------------------------------- -proc markAsClosure(owner: PSym; n: PNode) = +proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) = let s = n.sym if illegalCapture(s): - localError(n.info, "illegal capture '$1' of type <$2> which is declared here: $3" % + localError(g.config, n.info, "illegal capture '$1' of type <$2> which is declared here: $3" % [s.name.s, typeToString(s.typ), $s.info]) elif owner.typ.callConv notin {ccClosure, ccDefault}: - localError(n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % + localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % [s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]]) incl(owner.typ.flags, tfCapturesEnv) owner.typ.callConv = ccClosure @@ -290,12 +291,14 @@ type processed, capturedVars: IntSet ownerToType: Table[int, PType] somethingToDo: bool + graph: ModuleGraph -proc initDetectionPass(fn: PSym): DetectionPass = +proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass = result.processed = initIntSet() result.capturedVars = initIntSet() result.ownerToType = initTable[int, PType]() result.processed.incl(fn.id) + result.graph = g discard """ proc outer = @@ -312,7 +315,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym; result = c.ownerToType.getOrDefault(owner.id) if result.isNil: result = newType(tyRef, owner) - let obj = createEnvObj(owner, info) + let obj = createEnvObj(c.graph, owner, info) rawAddSon(result, obj) c.ownerToType[owner.id] = result @@ -321,13 +324,13 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = let obj = refObj.lastSon let fieldType = c.getEnvTypeForOwner(dep, info) #getHiddenParam(dep).typ if refObj == fieldType: - localError(dep.info, "internal error: invalid up reference computed") + localError(c.graph.config, dep.info, "internal error: invalid up reference computed") let upIdent = getIdent(upName) let upField = lookupInRecord(obj.n, upIdent) if upField != nil: if upField.typ != fieldType: - localError(dep.info, "internal error: up references do not agree") + localError(c.graph.config, dep.info, "internal error: up references do not agree") else: let result = newSym(skField, upIdent, obj.owner, obj.owner.info) result.typ = fieldType @@ -369,7 +372,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) = cp.typ = t addHiddenParam(fn, cp) elif cp.typ != t and fn.kind != skIterator: - localError(fn.info, "internal error: inconsistent environment type") + localError(c.graph.config, fn.info, "internal error: inconsistent environment type") #echo "adding closure to ", fn.name.s proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = @@ -395,7 +398,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = addClosureParam(c, owner, n.info) if interestingIterVar(s): if not c.capturedVars.containsOrIncl(s.id): - let obj = getHiddenParam(owner).typ.lastSon + let obj = getHiddenParam(c.graph, owner).typ.lastSon #let obj = c.getEnvTypeForOwner(s.owner).lastSon addField(obj, s) # but always return because the rest of the proc is only relevant when @@ -415,7 +418,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = """ # mark 'owner' as taking a closure: c.somethingToDo = true - markAsClosure(owner, n) + markAsClosure(c.graph, owner, n) addClosureParam(c, owner, n.info) #echo "capturing ", n.info # variable 's' is actually captured: @@ -440,7 +443,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = """ let up = w.skipGenericOwner #echo "up for ", w.name.s, " up ", up.name.s - markAsClosure(w, n) + markAsClosure(c.graph, w, n) addClosureParam(c, w, n.info) # , ow createUpField(c, w, up, n.info) w = up @@ -467,10 +470,10 @@ proc initLiftingPass(fn: PSym): LiftingPass = result.processed.incl(fn.id) result.envVars = initTable[int, PNode]() -proc accessViaEnvParam(n: PNode; owner: PSym): PNode = +proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode = let s = n.sym # Type based expression construction for simplicity: - let envParam = getHiddenParam(owner) + let envParam = getHiddenParam(g, owner) if not envParam.isNil: var access = newSymNode(envParam) while true: @@ -482,7 +485,7 @@ proc accessViaEnvParam(n: PNode; owner: PSym): PNode = let upField = lookupInRecord(obj.n, getIdent(upName)) if upField == nil: break access = rawIndirectAccess(access, upField, n.info) - localError(n.info, "internal error: environment misses: " & s.name.s) + localError(g.config, n.info, "internal error: environment misses: " & s.name.s) result = n proc newEnvVar(owner: PSym; typ: PType): PNode = @@ -501,22 +504,22 @@ proc newEnvVar(owner: PSym; typ: PType): PNode = proc setupEnvVar(owner: PSym; d: DetectionPass; c: var LiftingPass): PNode = if owner.isIterator: - return getHiddenParam(owner).newSymNode + return getHiddenParam(d.graph, owner).newSymNode result = c.envvars.getOrDefault(owner.id) if result.isNil: let envVarType = d.ownerToType.getOrDefault(owner.id) if envVarType.isNil: - localError owner.info, "internal error: could not determine closure type" + localError d.graph.config, owner.info, "internal error: could not determine closure type" result = newEnvVar(owner, envVarType) c.envVars[owner.id] = result -proc getUpViaParam(owner: PSym): PNode = - let p = getHiddenParam(owner) +proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode = + let p = getHiddenParam(g, owner) result = p.newSymNode if owner.isIterator: let upField = lookupInRecord(p.typ.lastSon.n, getIdent(upName)) if upField == nil: - localError(owner.info, "could not find up reference for closure iter") + localError(g.config, owner.info, "could not find up reference for closure iter") else: result = rawIndirectAccess(result, upField, p.info) @@ -526,7 +529,7 @@ proc rawClosureCreation(owner: PSym; var env: PNode if owner.isIterator: - env = getHiddenParam(owner).newSymNode + env = getHiddenParam(d.graph, owner).newSymNode else: env = setupEnvVar(owner, d, c) if env.kind == nkSym: @@ -534,7 +537,7 @@ proc rawClosureCreation(owner: PSym; addVar(v, env) result.add(v) # add 'new' statement: - result.add(newCall(getSysSym"internalNew", env)) + result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env)) # add assignment statements for captured parameters: for i in 1.. 0: - localError(n.info, "invalid control flow: 'yield' within a constructor") - let state = getStateField(owner) + localError(d.graph.config, n.info, "invalid control flow: 'yield' within a constructor") + let state = getStateField(d.graph, owner) assert state != nil assert state.typ != nil assert state.typ.n != nil @@ -615,7 +618,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass; var stateAsgnStmt = newNodeI(nkAsgn, n.info) stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)), state, n.info)) - stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt))) + stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, + getSysType(d.graph, n.info, tyInt))) var retStmt = newNodeI(nkReturnStmt, n.info) if n.sons[0].kind != nkEmpty: @@ -628,7 +632,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass; retStmt.add(emptyNode) var stateLabelStmt = newNodeI(nkState, n.info) - stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt))) + stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, + getSysType(d.graph, n.info, tyInt))) result = newNodeI(nkStmtList, n.info) result.add(stateAsgnStmt) @@ -637,16 +642,16 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass; proc transformReturn(n: PNode; owner: PSym; d: DetectionPass; c: var LiftingPass): PNode = - let state = getStateField(owner) + let state = getStateField(d.graph, owner) result = newNodeI(nkStmtList, n.info) var stateAsgnStmt = newNodeI(nkAsgn, n.info) stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)), state, n.info)) - stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt))) + stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(d.graph, n.info, tyInt))) result.add(stateAsgnStmt) result.add(n) -proc wrapIterBody(n: PNode; owner: PSym): PNode = +proc wrapIterBody(g: ModuleGraph; n: PNode; owner: PSym): PNode = if not owner.isIterator: return n when false: # unfortunately control flow is still convoluted and we can end up @@ -660,7 +665,7 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode = let info = n.info result = newNodeI(nkStmtList, info) var gs = newNodeI(nkGotoState, info) - gs.add(rawIndirectAccess(newSymNode(owner.getHiddenParam), getStateField(owner), info)) + gs.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)), getStateField(g, owner), info)) result.add(gs) var state0 = newNodeI(nkState, info) state0.add(newIntNode(nkIntLit, 0)) @@ -669,9 +674,9 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode = result.add(n) var stateAsgnStmt = newNodeI(nkAsgn, info) - stateAsgnStmt.add(rawIndirectAccess(newSymNode(owner.getHiddenParam), - getStateField(owner), info)) - stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt))) + stateAsgnStmt.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)), + getStateField(g, owner), info)) + stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(g, info, tyInt))) result.add(stateAsgnStmt) proc symToClosure(n: PNode; owner: PSym; d: DetectionPass; @@ -679,25 +684,25 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass; let s = n.sym if s == owner: # recursive calls go through (lambda, hiddenParam): - let available = getHiddenParam(owner) - result = makeClosure(s, available.newSymNode, n.info) + let available = getHiddenParam(d.graph, owner) + result = makeClosure(d.graph, s, available.newSymNode, n.info) elif s.isIterator: result = closureCreationForIter(n, d, c) elif s.skipGenericOwner == owner: # direct dependency, so use the outer's env variable: - result = makeClosure(s, setupEnvVar(owner, d, c), n.info) + result = makeClosure(d.graph, s, setupEnvVar(owner, d, c), n.info) else: - let available = getHiddenParam(owner) - let wanted = getHiddenParam(s).typ + let available = getHiddenParam(d.graph, owner) + let wanted = getHiddenParam(d.graph, s).typ # ugh: call through some other inner proc; var access = newSymNode(available) while true: if access.typ == wanted: - return makeClosure(s, access, n.info) + return makeClosure(d.graph, s, access, n.info) let obj = access.typ.sons[0] let upField = lookupInRecord(obj.n, getIdent(upName)) if upField == nil: - localError(n.info, "internal error: no environment found") + localError(d.graph.config, n.info, "internal error: no environment found") return n access = rawIndirectAccess(access, upField, n.info) @@ -713,7 +718,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; # echo renderTree(s.getBody, {renderIds}) let oldInContainer = c.inContainer c.inContainer = 0 - let body = wrapIterBody(liftCapturedVars(s.getBody, s, d, c), s) + let body = wrapIterBody(d.graph, liftCapturedVars(s.getBody, s, d, c), s) if c.envvars.getOrDefault(s.id).isNil: s.ast.sons[bodyPos] = body else: @@ -723,9 +728,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; result = symToClosure(n, owner, d, c) elif s.id in d.capturedVars: if s.owner != owner: - result = accessViaEnvParam(n, owner) + result = accessViaEnvParam(d.graph, n, owner) elif owner.isIterator and interestingIterVar(s): - result = accessViaEnvParam(n, owner) + result = accessViaEnvParam(d.graph, n, owner) else: result = accessViaEnvVar(n, owner, d, c) of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom, @@ -791,8 +796,8 @@ proc semCaptureSym*(s, owner: PSym) = # since the analysis is not entirely correct, we don't set 'tfCapturesEnv' # here -proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode = - var d = initDetectionPass(fn) +proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNode = + var d = initDetectionPass(g, fn) var c = initLiftingPass(fn) # pretend 'fn' is a closure iterator for the analysis: let oldKind = fn.kind @@ -801,11 +806,11 @@ proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode = fn.typ.callConv = ccClosure d.ownerToType[fn.id] = ptrType detectCapturedVars(body, fn, d) - result = wrapIterBody(liftCapturedVars(body, fn, d, c), fn) + result = wrapIterBody(g, liftCapturedVars(body, fn, d, c), fn) fn.kind = oldKind fn.typ.callConv = oldCC -proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode = +proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode = # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs # the transformation even when compiling to JS ... @@ -819,7 +824,7 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode = result = body tooEarly = true else: - var d = initDetectionPass(fn) + var d = initDetectionPass(g, fn) detectCapturedVars(body, fn, d) if not d.somethingToDo and fn.isIterator: addClosureParam(d, fn, body.info) @@ -829,7 +834,7 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode = var newBody = liftCapturedVars(body, fn, d, c) if c.envvars.getOrDefault(fn.id) != nil: newBody = newTree(nkStmtList, rawClosureCreation(fn, d, c), newBody) - result = wrapIterBody(newBody, fn) + result = wrapIterBody(g, newBody, fn) else: result = body #if fn.name.s == "get2": @@ -845,7 +850,7 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode = # ------------------- iterator transformation -------------------------------- -proc liftForLoop*(body: PNode; owner: PSym): PNode = +proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode = # problem ahead: the iterator could be invoked indirectly, but then # we don't know what environment to create here: # @@ -876,7 +881,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode = if liftingHarmful(owner): return body var L = body.len if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds): - localError(body.info, "ignored invalid for loop") + localError(g.config, body.info, "ignored invalid for loop") return body var call = body[L-2] @@ -889,7 +894,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode = # createClosure() let iter = op.sym - let hp = getHiddenParam(iter) + let hp = getHiddenParam(g, iter) env = newSym(skLet, iter.name, owner, body.info) env.typ = hp.typ env.flags = hp.flags @@ -898,7 +903,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode = addVar(v, newSymNode(env)) result.add(v) # add 'new' statement: - result.add(newCall(getSysSym"internalNew", env.newSymNode)) + result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode)) elif op.kind == nkStmtListExpr: let closure = op.lastSon if closure.kind == nkClosure: @@ -908,7 +913,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode = var loopBody = newNodeI(nkStmtList, body.info, 3) var whileLoop = newNodeI(nkWhileStmt, body.info, 2) - whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool)) + whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(g, body.info, tyBool)) whileLoop.sons[1] = loopBody result.add whileLoop @@ -923,7 +928,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode = addSon(vpart, ast.emptyNode) # no explicit type if not env.isNil: - call.sons[0] = makeClosure(call.sons[0].sym, env.newSymNode, body.info) + call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info) addSon(vpart, call) addSon(v2, vpart) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 8510bf7ee7..5b85ab008f 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -12,18 +12,18 @@ const genPrefix* = ":tmp" # prefix for generated names -import ast, astalgo, types, idents, magicsys, msgs, options +import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs from trees import getMagic proc newDeref*(n: PNode): PNode {.inline.} = result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0]) addSon(result, n) -proc newTupleAccess*(tup: PNode, i: int): PNode = +proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode = result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes( abstractInst).sons[i]) addSon(result, copyTree(tup)) - var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt)) + var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt)) lit.intVal = i addSon(result, lit) @@ -44,7 +44,7 @@ proc newFastAsgnStmt(le, ri: PNode): PNode = result.sons[0] = le result.sons[1] = ri -proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode = +proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode = assert n.kind == nkVarTuple let value = n.lastSon result = newNodeI(nkStmtList, n.info) @@ -61,7 +61,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode = result.add newAsgnStmt(tempAsNode, value) for i in 0 .. n.len-3: if n.sons[i].kind == nkSym: v.addVar(n.sons[i]) - result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i)) + result.add newAsgnStmt(n.sons[i], newTupleAccess(g, tempAsNode, i)) proc newTupleAccessRaw*(tup: PNode, i: int): PNode = result = newNodeI(nkBracketExpr, tup.info) @@ -112,13 +112,13 @@ proc lowerSwap*(n: PNode; owner: PSym): PNode = result.add newFastAsgnStmt(n[1], n[2]) result.add newFastAsgnStmt(n[2], tempAsNode) -proc createObj*(owner: PSym, info: TLineInfo; final=true): PType = +proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType = result = newType(tyObject, owner) if final: rawAddSon(result, nil) incl result.flags, tfFinal else: - rawAddSon(result, getCompilerProc("RootObj").typ) + rawAddSon(result, getCompilerProc(g, "RootObj").typ) result.n = newNodeI(nkRecList, info) let s = newSym(skType, getIdent("Env_" & info.toFilename), owner, info) @@ -218,7 +218,7 @@ proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode = #if field == nil: # echo "FIELD ", b # debug deref.typ - internalAssert field != nil + assert field != nil addSon(deref, a) result = newNodeI(nkDotExpr, info) addSon(result, deref) @@ -242,7 +242,7 @@ proc indirectAccess(a: PNode, b: string, info: TLineInfo): PNode = #if field == nil: # echo "FIELD ", b # debug deref.typ - internalAssert field != nil + assert field != nil addSon(deref, a) result = newNodeI(nkDotExpr, info) addSon(result, deref) @@ -278,12 +278,12 @@ proc genDeref*(n: PNode): PNode = n.typ.skipTypes(abstractInst).sons[0]) result.add n -proc callCodegenProc*(name: string, arg1: PNode; +proc callCodegenProc*(g: ModuleGraph; name: string, arg1: PNode; arg2, arg3, optionalArgs: PNode = nil): PNode = result = newNodeI(nkCall, arg1.info) - let sym = magicsys.getCompilerProc(name) + let sym = magicsys.getCompilerProc(g, name) if sym == nil: - localError(arg1.info, errSystemNeeds, name) + localError(g.config, arg1.info, "system module needs: " & name) else: result.add newSymNode(sym) result.add arg1 @@ -333,7 +333,7 @@ proc typeNeedsNoDeepCopy(t: PType): bool = if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon result = not containsGarbageCollectedRef(t) -proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType; +proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType; v: PNode; useShallowCopy=false): PSym = result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info) result.typ = typ @@ -349,7 +349,7 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType; varInit.add newFastAsgnStmt(newSymNode(result), v) else: let deepCopyCall = newNodeI(nkCall, varInit.info, 3) - deepCopyCall.sons[0] = newSymNode(getSysMagic("deepCopy", mDeepCopy)) + deepCopyCall.sons[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy)) deepCopyCall.sons[1] = newSymNode(result) deepCopyCall.sons[2] = v varInit.add deepCopyCall @@ -384,23 +384,23 @@ stmtList: """ -proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; +proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; varSection, varInit, call, barrier, fv: PNode; spawnKind: TSpawnResult): PSym = var body = newNodeI(nkStmtList, f.info) var threadLocalBarrier: PSym if barrier != nil: var varSection2 = newNodeI(nkVarSection, barrier.info) - threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, + threadLocalBarrier = addLocalVar(g, varSection2, nil, argsParam.owner, barrier.typ, barrier) body.add varSection2 - body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode) + body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.newSymNode) var threadLocalProm: PSym if spawnKind == srByVar: - threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv) + threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv) elif fv != nil: - internalAssert fv.typ.kind == tyGenericInst - threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv) + internalAssert g.config, fv.typ.kind == tyGenericInst + threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv) body.add varSection body.add varInit if fv != nil and spawnKind != srByVar: @@ -409,30 +409,30 @@ 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(g, "nimArgsPassingDone", threadParam.newSymNode) if spawnKind == srByVar: body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call) elif fv != nil: let fk = fv.typ.sons[1].flowVarKind if fk == fvInvalid: - localError(f.info, "cannot create a flowVar of type: " & + localError(g.config, f.info, "cannot create a flowVar of type: " & typeToString(fv.typ.sons[1])) body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, if fk == fvGC: "data" else: "blob", fv.info), call) if fk == fvGC: let incRefCall = newNodeI(nkCall, fv.info, 2) - incRefCall.sons[0] = newSymNode(getSysMagic("GCref", mGCref)) + incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref)) incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode, "data", fv.info) body.add incRefCall 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(g, "nimFlowVarSignal", threadLocalProm.newSymNode) else: body.add call if barrier != nil: - body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode) + body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.newSymNode) var params = newNodeI(nkFormalParams, f.info) params.add emptyNode @@ -460,7 +460,7 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode = result.typ = newType(tyPtr, objType.owner) result.typ.rawAddSon(objType) -proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, +proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym, castExpr, call, varSection, varInit, result: PNode) = let formals = n[0].typ.n @@ -470,7 +470,7 @@ proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, # 'tyOpenArray': var argType = n[i].typ.skipTypes(abstractInst) if i < formals.len and formals[i].typ.kind in {tyVar, tyLent}: - localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter") + localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter") #elif containsTyRef(argType): # localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure") @@ -480,7 +480,7 @@ proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, objType.addField(field) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) - let temp = addLocalVar(varSection, varInit, objType.owner, argType, + let temp = addLocalVar(g, varSection, varInit, objType.owner, argType, indirectAccess(castExpr, field, n.info)) call.add(newSymNode(temp)) @@ -501,20 +501,20 @@ proc getRoot*(n: PNode): PSym = if getMagic(n) == mSlice: result = getRoot(n.sons[1]) else: discard -proc newIntLit*(value: BiggestInt): PNode = +proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode = result = nkIntLit.newIntNode(value) - result.typ = getSysType(tyInt) + result.typ = getSysType(g, info, tyInt) -proc genHigh*(n: PNode): PNode = +proc genHigh*(g: ModuleGraph; n: PNode): PNode = if skipTypes(n.typ, abstractVar).kind == tyArray: - result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar))) + result = newIntLit(g, n.info, lastOrd(skipTypes(n.typ, abstractVar))) else: result = newNodeI(nkCall, n.info, 2) - result.typ = getSysType(tyInt) - result.sons[0] = newSymNode(getSysMagic("high", mHigh)) + result.typ = getSysType(g, n.info, tyInt) + result.sons[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh)) result.sons[1] = n -proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; +proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym; castExpr, call, varSection, varInit, result: PNode) = let formals = n[0].typ.n @@ -535,10 +535,10 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; # important special case: we always create a zero-copy slice: let slice = newNodeI(nkCall, n.info, 4) slice.typ = n.typ - slice.sons[0] = newSymNode(createMagic("slice", mSlice)) - slice.sons[0].typ = getSysType(tyInt) # fake type + slice.sons[0] = newSymNode(createMagic(g, "slice", mSlice)) + slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type var fieldB = newSym(skField, tmpName, objType.owner, n.info) - fieldB.typ = getSysType(tyInt) + fieldB.typ = getSysType(g, n.info, tyInt) objType.addField(fieldB) if getMagic(n) == mSlice: @@ -548,12 +548,12 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) var fieldA = newSym(skField, tmpName, objType.owner, n.info) - fieldA.typ = getSysType(tyInt) + fieldA.typ = getSysType(g, n.info, tyInt) objType.addField(fieldA) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3]) - let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ, + let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldA.typ, indirectAccess(castExpr, fieldA, n.info), useShallowCopy=true) slice.sons[2] = threadLocal.newSymNode @@ -562,13 +562,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; field.typ = a.typ objType.addField(field) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(n)) + result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n)) - slice.sons[2] = newIntLit(0) + slice.sons[2] = newIntLit(g, n.info, 0) # the array itself does not need to go through a thread local variable: slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info)) - let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ, + let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldB.typ, indirectAccess(castExpr, fieldB, n.info), useShallowCopy=true) slice.sons[3] = threadLocal.newSymNode @@ -580,7 +580,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; field.typ = a.typ objType.addField(field) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ, + let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ, indirectAccess(castExpr, field, n.info), useShallowCopy=true) call.add(genDeref(threadLocal.newSymNode)) @@ -589,13 +589,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; field.typ = argType objType.addField(field) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n) - let threadLocal = addLocalVar(varSection, varInit, + let threadLocal = addLocalVar(g, varSection, varInit, objType.owner, field.typ, indirectAccess(castExpr, field, n.info), useShallowCopy=true) call.add(threadLocal.newSymNode) -proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; +proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: PType; barrier, dest: PNode = nil): PNode = # if 'barrier' != nil, then it is in a 'parallel' section and we # generate quite different code @@ -603,31 +603,31 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; let spawnKind = spawnResult(retType, barrier!=nil) case spawnKind of srVoid: - internalAssert dest == nil + internalAssert g.config, dest == nil result = newNodeI(nkStmtList, n.info) of srFlowVar: - internalAssert dest == nil + internalAssert g.config, dest == nil result = newNodeIT(nkStmtListExpr, n.info, retType) of srByVar: - if dest == nil: localError(n.info, "'spawn' must not be discarded") + if dest == nil: localError(g.config, n.info, "'spawn' must not be discarded") result = newNodeI(nkStmtList, n.info) if n.kind notin nkCallKinds: - localError(n.info, "'spawn' takes a call expression") + localError(g.config, n.info, "'spawn' takes a call expression") return if optThreadAnalysis in gGlobalOptions: if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}: - localError(n.info, "'spawn' takes a GC safe call expression") + localError(g.config, n.info, "'spawn' takes a GC safe call expression") var threadParam = newSym(skParam, getIdent"thread", owner, n.info) argsParam = newSym(skParam, getIdent"args", owner, n.info) block: - let ptrType = getSysType(tyPointer) + let ptrType = getSysType(g, n.info, tyPointer) threadParam.typ = ptrType argsParam.typ = ptrType argsParam.position = 1 - var objType = createObj(owner, n.info) + var objType = createObj(g, owner, n.info) incl(objType.flags, tfFinal) let castExpr = createCastExpr(argsParam, objType) @@ -644,7 +644,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; # templates and macros are in fact valid here due to the nature of # the transformation: if fn.kind == nkClosure: - localError(n.info, "closure in spawn environment is not allowed") + localError(g.config, n.info, "closure in spawn environment is not allowed") if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro, skFunc, skMethod, skConverter}): # for indirect calls we pass the function pointer in the scratchObj @@ -655,24 +655,24 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) fn = indirectAccess(castExpr, field, n.info) elif fn.kind == nkSym and fn.sym.kind == skIterator: - localError(n.info, "iterator in spawn environment is not allowed") + localError(g.config, n.info, "iterator in spawn environment is not allowed") elif fn.typ.callConv == ccClosure: - localError(n.info, "closure in spawn environment is not allowed") + localError(g.config, n.info, "closure in spawn environment is not allowed") call.add(fn) var varSection = newNodeI(nkVarSection, n.info) var varInit = newNodeI(nkStmtList, n.info) if barrier.isNil: - setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, + setupArgsForConcurrency(g, n, objType, scratchObj, castExpr, call, varSection, varInit, result) else: - setupArgsForParallelism(n, objType, scratchObj, castExpr, call, + setupArgsForParallelism(g, n, objType, scratchObj, castExpr, call, varSection, varInit, result) var barrierAsExpr: PNode = nil if barrier != nil: let typ = newType(tyPtr, owner) - typ.rawAddSon(magicsys.getCompilerProc("Barrier").typ) + typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) var field = newSym(skField, getIdent"barrier", owner, n.info) field.typ = typ objType.addField(field) @@ -689,7 +689,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; # create flowVar: result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1])) if barrier == nil: - result.add callCodegenProc("nimFlowVarCreateSemaphore", fvField) + result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField) elif spawnKind == srByVar: var field = newSym(skField, getIdent"fv", owner, n.info) @@ -699,10 +699,10 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; fvAsExpr = indirectAccess(castExpr, field, n.info) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) - let wrapper = createWrapperProc(fn, threadParam, argsParam, + let wrapper = createWrapperProc(g, fn, threadParam, argsParam, varSection, varInit, call, barrierAsExpr, fvAsExpr, spawnKind) - result.add callCodegenProc("nimSpawn" & $spawnExpr.len, wrapper.newSymNode, + result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapper.newSymNode, genAddrOf(scratchObj.newSymNode), nil, spawnExpr) if spawnKind == srFlowVar: result.add fvField From fedc136985948a5b011a74ef49f97e43f2a3fe72 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 09:38:41 +0200 Subject: [PATCH 186/214] transf and vmgen compile again --- compiler/destroyer.nim | 49 +++++----- compiler/dfa.nim | 14 +-- compiler/gorgeimpl.nim | 4 +- compiler/liftlocals.nim | 6 +- compiler/transf.nim | 89 +++++++++--------- compiler/vmdef.nim | 8 +- compiler/vmdeps.nim | 10 +- compiler/vmgen.nim | 204 ++++++++++++++++++++-------------------- compiler/vmmarshal.nim | 73 +++++++------- 9 files changed, 234 insertions(+), 223 deletions(-) diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index cd16469de3..31c7357941 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -116,7 +116,8 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - strutils, options, dfa, lowerings, rodread, tables + strutils, options, dfa, lowerings, rodread, tables, modulegraphs, + configuration const InterestingSyms = {skVar, skResult, skLet} @@ -130,6 +131,7 @@ type tmp: PSym destroys, topLevelVars: PNode toDropBit: Table[int, PSym] + graph: ModuleGraph proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = # XXX why are temps fields in an object here? @@ -222,21 +224,21 @@ proc patchHead(s: PSym) = template genOp(opr, opname) = let op = opr if op == nil: - globalError(dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t)) + globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t)) elif op.ast[genericParamsPos].kind != nkEmpty: - globalError(dest.info, "internal error: '" & opname & "' operator is generic") + globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator is generic") patchHead op result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest)) -proc genSink(t: PType; dest: PNode): PNode = +proc genSink(c: Con; t: PType; dest: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) genOp(if t.sink != nil: t.sink else: t.assignment, "=sink") -proc genCopy(t: PType; dest: PNode): PNode = +proc genCopy(c: Con; t: PType; dest: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) genOp(t.assignment, "=") -proc genDestroy(t: PType; dest: PNode): PNode = +proc genDestroy(c: Con; t: PType; dest: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) genOp(t.destructor, "=destroy") @@ -249,14 +251,14 @@ proc dropBit(c: var Con; s: PSym): PSym = proc registerDropBit(c: var Con; s: PSym) = let result = newSym(skTemp, getIdent(s.name.s & "_AliveBit"), c.owner, s.info) - result.typ = getSysType(tyBool) + result.typ = getSysType(c.graph, s.info, tyBool) let trueVal = newIntTypeNode(nkIntLit, 1, result.typ) c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, emptyNode, trueVal) c.toDropBit[s.id] = result # generate: # if not sinkParam_AliveBit: `=destroy`(sinkParam) c.destroys.add newTree(nkIfStmt, - newTree(nkElifBranch, newSymNode result, genDestroy(s.typ, newSymNode s))) + newTree(nkElifBranch, newSymNode result, genDestroy(c, s.typ, newSymNode s))) proc p(n: PNode; c: var Con): PNode @@ -274,36 +276,36 @@ proc destructiveMoveSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let bit = newSymNode dropBit(c, n.sym) if optMoveCheck in c.owner.options: - result.add callCodegenProc("chckMove", bit) + result.add callCodegenProc(c.graph, "chckMove", bit) result.add newTree(nkAsgn, bit, - newIntTypeNode(nkIntLit, 0, getSysType(tyBool))) + newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool))) result.add n proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = if ri.kind in constrExprs: - result = genSink(ri.typ, dest) + result = genSink(c, ri.typ, dest) # watch out and no not transform 'ri' twice if it's a call: let ri2 = copyNode(ri) recurse(ri, ri2) result.add ri2 elif ri.kind == nkSym and isHarmlessVar(ri.sym, c): - result = genSink(ri.typ, dest) + result = genSink(c, ri.typ, dest) result.add p(ri, c) elif ri.kind == nkSym and isSinkParam(ri.sym): - result = genSink(ri.typ, dest) + result = genSink(c, ri.typ, dest) result.add destructiveMoveSink(ri, c) else: - result = genCopy(ri.typ, dest) + result = genCopy(c, ri.typ, dest) result.add p(ri, c) proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = getTemp(c, n.typ, n.info) if hasDestructor(n.typ): - var m = genCopy(n.typ, tmp) + var m = genCopy(c, n.typ, tmp) m.add p(n, c) result.add m - message(n.info, hintPerformance, + message(c.graph.config, n.info, hintPerformance, "passing '$1' to a sink parameter introduces an implicit copy; " & "use 'move($1)' to prevent it" % $n) else: @@ -312,7 +314,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = proc genReset(n: PNode; c: var Con): PNode = result = newNodeI(nkCall, n.info) - result.add(newSymNode(createMagic("reset", mReset))) + result.add(newSymNode(createMagic(c.graph, "reset", mReset))) # The mReset builtin does not take the address: result.add n @@ -345,7 +347,7 @@ proc p(n: PNode; c: var Con): PNode = let L = it.len-1 let ri = it[L] if it.kind == nkVarTuple and hasDestructor(ri.typ): - let x = lowerTupleUnpacking(it, c.owner) + let x = lowerTupleUnpacking(c.graph, it, c.owner) result.add p(x, c) elif it.kind == nkIdentDefs and hasDestructor(it[0].typ): for j in 0..L-2: @@ -354,7 +356,7 @@ proc p(n: PNode; c: var Con): PNode = # move the variable declaration to the top of the frame: c.addTopVar v # make sure it's destroyed at the end of the proc: - c.destroys.add genDestroy(v.typ, v) + c.destroys.add genDestroy(c, v.typ, v) if ri.kind != nkEmpty: let r = moveOrCopy(v, ri, c) result.add r @@ -400,11 +402,11 @@ proc p(n: PNode; c: var Con): PNode = discard "produce temp creation" result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = getTemp(c, n.typ, n.info) - var sinkExpr = genSink(n.typ, tmp) + var sinkExpr = genSink(c, n.typ, tmp) sinkExpr.add n result.add sinkExpr result.add tmp - c.destroys.add genDestroy(n.typ, tmp) + c.destroys.add genDestroy(c, n.typ, tmp) else: result = n of nkAsgn, nkFastAsgn: @@ -420,17 +422,18 @@ proc p(n: PNode; c: var Con): PNode = result = copyNode(n) recurse(n, result) -proc injectDestructorCalls*(owner: PSym; n: PNode): PNode = +proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = when defined(nimDebugDestroys): echo "injecting into ", n var c: Con c.owner = owner c.tmp = newSym(skTemp, getIdent":d", owner, n.info) - c.tmpObj = createObj(owner, n.info) + c.tmpObj = createObj(g, owner, n.info) c.tmp.typ = c.tmpObj c.destroys = newNodeI(nkStmtList, n.info) c.topLevelVars = newNodeI(nkVarSection, n.info) c.toDropBit = initTable[int, PSym]() + c.graph = g let cfg = constructCfg(owner, n) shallowCopy(c.g, cfg) c.jumpTargets = initIntSet() diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 0784151af8..0fd7061781 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -23,7 +23,7 @@ ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf -import ast, astalgo, types, intsets, tables, msgs +import ast, astalgo, types, intsets, tables, msgs, options type InstrKind* = enum @@ -160,7 +160,7 @@ proc genBreak(c: var Con; n: PNode) = if c.blocks[i].label == n.sons[0].sym: c.blocks[i].fixups.add L1 return - globalError(n.info, errGenerated, "VM problem: cannot find 'break' target") + #globalError(n.info, "VM problem: cannot find 'break' target") else: c.blocks[c.blocks.high].fixups.add L1 @@ -334,7 +334,7 @@ proc gen(c: var Con; n: PNode) = of nkVarSection, nkLetSection: genVarSection(c, n) else: discard -proc dfa(code: seq[Instr]) = +proc dfa(code: seq[Instr]; conf: ConfigRef) = var u = newSeq[IntSet](code.len) # usages var d = newSeq[IntSet](code.len) # defs var c = newSeq[IntSet](code.len) # consumed @@ -426,17 +426,17 @@ proc dfa(code: seq[Instr]) = of use, useWithinCall: let s = code[i].sym if s.id notin d[i]: - localError(code[i].n.info, "usage of uninitialized variable: " & s.name.s) + localError(conf, code[i].n.info, "usage of uninitialized variable: " & s.name.s) if s.id in c[i]: - localError(code[i].n.info, "usage of an already consumed variable: " & s.name.s) + localError(conf, code[i].n.info, "usage of an already consumed variable: " & s.name.s) else: discard -proc dataflowAnalysis*(s: PSym; body: PNode) = +proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) = var c = Con(code: @[], blocks: @[]) gen(c, body) when defined(useDfa) and defined(debugDfa): echoCfg(c.code) - dfa(c.code) + dfa(c.code, conf) proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph = ## constructs a control flow graph for ``body``. diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index 80302b4b5e..44c7651bca 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -21,11 +21,11 @@ proc readOutput(p: Process): (string, int) = result[0].setLen(result[0].len - "\n".len) result[1] = p.waitForExit -proc opGorge*(cmd, input, cache: string, info: TLineInfo): (string, int) = +proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) = let workingDir = parentDir(info.toFullPath) if cache.len > 0:# and optForceFullMake notin gGlobalOptions: let h = secureHash(cmd & "\t" & input & "\t" & cache) - let filename = options.toGeneratedFile("gorge_" & $h, "txt") + let filename = options.toGeneratedFile(conf, "gorge_" & $h, "txt") var f: File if open(f, filename): result = (f.readAll, 0) diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim index 3610a14862..4603d357b2 100644 --- a/compiler/liftlocals.nim +++ b/compiler/liftlocals.nim @@ -52,17 +52,17 @@ proc lookupParam(params, dest: PNode): PSym = if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id: return params[i].sym -proc liftLocalsIfRequested*(prc: PSym; n: PNode): PNode = +proc liftLocalsIfRequested*(prc: PSym; n: PNode; conf: ConfigRef): PNode = let liftDest = getPragmaVal(prc.ast, wLiftLocals) if liftDest == nil: return n let partialParam = lookupParam(prc.typ.n, liftDest) if partialParam.isNil: - localError(liftDest.info, "'$1' is not a parameter of '$2'" % + localError(conf, liftDest.info, "'$1' is not a parameter of '$2'" % [$liftDest, prc.name.s]) return n let objType = partialParam.typ.skipTypes(abstractPtrs) if objType.kind != tyObject or tfPartial notin objType.flags: - localError(liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest) + localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest) return n var c = Ctx(partialParam: partialParam, objType: objType) let w = newTree(nkStmtList, n) diff --git a/compiler/transf.nim b/compiler/transf.nim index f7ec6c97f2..e49d51b110 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -21,7 +21,8 @@ import intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread, - lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals + lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals, + modulegraphs type PTransNode* = distinct PNode @@ -44,6 +45,7 @@ type nestedProcs: int # > 0 if we are in a nested proc contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' deferDetected, tooEarly, needsDestroyPass: bool + graph: ModuleGraph PTransf = ref TTransfContext proc newTransNode(a: PNode): PTransNode {.inline.} = @@ -84,7 +86,7 @@ proc pushTransCon(c: PTransf, t: PTransCon) = c.transCon = t proc popTransCon(c: PTransf) = - if (c.transCon == nil): internalError("popTransCon") + if (c.transCon == nil): internalError(c.graph.config, "popTransCon") c.transCon = c.transCon.next proc getCurrOwner(c: PTransf): PSym = @@ -97,7 +99,7 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode = incl(r.flags, sfFromGeneric) let owner = getCurrOwner(c) if owner.isIterator and not c.tooEarly: - result = freshVarForClosureIter(r, owner) + result = freshVarForClosureIter(c.graph, r, owner) else: result = newSymNode(r) @@ -118,10 +120,10 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = if s.typ != nil and s.typ.callConv == ccClosure: if s.kind == skIterator: if c.tooEarly: return n - else: return liftIterSym(n, getCurrOwner(c)) + else: return liftIterSym(c.graph, n, getCurrOwner(c)) elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly: # top level .closure procs are still somewhat supported for 'Nake': - return makeClosure(s, nil, n.info) + return makeClosure(c.graph, s, nil, n.info) #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure: # echo n.info, " come heer for ", c.tooEarly # if not c.tooEarly: @@ -130,7 +132,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = if sfBorrow in s.flags and s.kind in routineKinds: # simply exchange the symbol: b = s.getBody - if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol") + if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol") b = newSymNode(b.sym, n.info) else: b = n @@ -151,7 +153,7 @@ proc transformSym(c: PTransf, n: PNode): PTransNode = proc freshVar(c: PTransf; v: PSym): PNode = let owner = getCurrOwner(c) if owner.isIterator and not c.tooEarly: - result = freshVarForClosureIter(v, owner) + result = freshVarForClosureIter(c.graph, v, owner) else: var newVar = copySym(v) incl(newVar.flags, sfFromGeneric) @@ -166,11 +168,11 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode = result[i] = PTransNode(it) elif it.kind == nkIdentDefs: if it.sons[0].kind == nkSym: - internalAssert(it.len == 3) + internalAssert(c.graph.config, it.len == 3) let x = freshVar(c, it.sons[0].sym) idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x) var defs = newTransNode(nkIdentDefs, it.info, 3) - if importantComments(): + if importantComments(c.graph.config): # keep documentation information: PNode(defs).comment = it.comment defs[0] = x.PTransNode @@ -184,7 +186,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode = result[i] = transform(c, it) else: if it.kind != nkVarTuple: - internalError(it.info, "transformVarSection: not nkVarTuple") + internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple") var L = sonsLen(it) var defs = newTransNode(it.kind, it.info, L) for j in countup(0, L-3): @@ -203,9 +205,9 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode = if it.kind == nkCommentStmt: result[i] = PTransNode(it) else: - if it.kind != nkConstDef: internalError(it.info, "transformConstSection") + if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection") if it.sons[0].kind != nkSym: - internalError(it.info, "transformConstSection") + internalError(c.graph.config, it.info, "transformConstSection") result[i] = PTransNode(it) @@ -301,7 +303,7 @@ proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) = # XXX: BUG: what if `n` is an expression with side-effects? for i in countup(0, sonsLen(c.transCon.forStmt) - 3): add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i], - transform(c, newTupleAccess(n, i)))) + transform(c, newTupleAccess(c.graph, n, i)))) proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode = case n.kind @@ -382,7 +384,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = if n.typ.skipTypes(abstractVar).kind != tyOpenArray: PNode(result).typ = n.typ -proc generateThunk(prc: PNode, dest: PType): PNode = +proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode = ## Converts 'prc' into '(thunk, nil)' so that it's compatible with ## a closure. @@ -394,9 +396,9 @@ proc generateThunk(prc: PNode, dest: PType): PNode = conv.add(emptyNode) conv.add(prc) if prc.kind == nkClosure: - internalError(prc.info, "closure to closure created") + internalError(c.graph.config, prc.info, "closure to closure created") result.add(conv) - result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil))) + result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil))) proc transformConv(c: PTransf, n: PNode): PTransNode = # numeric types need range checks: @@ -481,7 +483,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = of tyProc: result = transformSons(c, n) if dest.callConv == ccClosure and source.callConv == ccDefault: - result = generateThunk(result[1].PNode, dest).PTransNode + result = generateThunk(c, result[1].PNode, dest).PTransNode else: result = transformSons(c, n) @@ -513,7 +515,7 @@ proc findWrongOwners(c: PTransf, n: PNode) = if n.kind == nkVarSection: let x = n.sons[0].sons[0] if x.kind == nkSym and x.sym.owner != getCurrOwner(c): - internalError(x.info, "bah " & x.sym.name.s & " " & + internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " & x.sym.owner.name.s & " " & getCurrOwner(c).name.s) else: for i in 0 ..< safeLen(n): findWrongOwners(c, n.sons[i]) @@ -521,7 +523,7 @@ proc findWrongOwners(c: PTransf, n: PNode) = proc transformFor(c: PTransf, n: PNode): PTransNode = # generate access statements for the parameters (unless they are constant) # put mapping from formal parameters to actual parameters - if n.kind != nkForStmt: internalError(n.info, "transformFor") + if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor") var length = sonsLen(n) var call = n.sons[length - 2] @@ -539,7 +541,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode if not c.tooEarly: n.sons[length-2] = transform(c, n.sons[length-2]).PNode - result[1] = lambdalifting.liftForLoop(n, getCurrOwner(c)).PTransNode + result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode else: result[1] = newNode(nkEmpty).PTransNode discard c.breakSyms.pop @@ -689,7 +691,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = while (j < sonsLen(n)): let b = transform(c, n.sons[j]).PNode if not isConstExpr(b): break - a = evalOp(op.magic, n, a, b, nil) + a = evalOp(op.magic, n, a, b, nil, c.graph) inc(j) add(result, a.PTransNode) if len(result) == 2: result = result[1] @@ -708,7 +710,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = let t = lastSon(s.sons[0].sym.ast) if t.kind != nkSym or sfDispatcher notin t.sym.flags: methodDef(s.sons[0].sym, false) - result = methodCall(s).PTransNode + result = methodCall(s, c.graph.config).PTransNode else: result = s.PTransNode @@ -719,7 +721,7 @@ proc transformExceptBranch(c: PTransf, n: PNode): PTransNode = let actions = newTransNode(nkStmtListExpr, n[1], 2) # Generating `let exc = (excType)(getCurrentException())` # -> getCurrentException() - let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode)) + let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException", ast.emptyNode)) # -> (excType) let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2) convNode[0] = PTransNode(ast.emptyNode) @@ -748,10 +750,10 @@ proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} = result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and cnst.len != 0 -proc commonOptimizations*(c: PSym, n: PNode): PNode = +proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode = result = n for i in 0 ..< n.safeLen: - result.sons[i] = commonOptimizations(c, n.sons[i]) + result.sons[i] = commonOptimizations(g, c, n.sons[i]) var op = getMergeOp(n) if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3): result = newNodeIT(nkCall, n.info, n.typ) @@ -766,12 +768,12 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode = while j < sonsLen(args): let b = args.sons[j] if not isConstExpr(b): break - a = evalOp(op.magic, result, a, b, nil) + a = evalOp(op.magic, result, a, b, nil, g) inc(j) add(result, a) if len(result) == 2: result = result[1] else: - var cnst = getConstExpr(c, n) + var cnst = getConstExpr(c, n, g) # we inline constants if they are not complex constants: if cnst != nil and not dontInlineConstant(n, cnst): result = cnst @@ -888,7 +890,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = let L = n.len-1 result[L] = transform(c, n.sons[L]) # XXX comment handling really sucks: - if importantComments(): + if importantComments(c.graph.config): PNode(result).comment = n.comment of nkClosure: # it can happen that for-loop-inlining produced a fresh @@ -905,7 +907,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = when false: if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor - var cnst = getConstExpr(c.module, PNode(result)) + var cnst = getConstExpr(c.module, PNode(result), c.graph) # we inline constants if they are not complex constants: if cnst != nil and not dontInlineConstant(n, cnst): result = PTransNode(cnst) # do not miss an optimization @@ -920,11 +922,12 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode = popTransCon(c) incl(result.flags, nfTransf) -proc openTransf(module: PSym, filename: string): PTransf = +proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf = new(result) result.contSyms = @[] result.breakSyms = @[] result.module = module + result.graph = g proc flattenStmts(n: PNode) = var goOn = true @@ -967,46 +970,46 @@ template liftDefer(c, root) = if c.deferDetected: liftDeferAux(root) -proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = +proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode = if nfTransf in n.flags or prc.kind in {skTemplate}: result = n else: - var c = openTransf(module, "") - result = liftLambdas(prc, n, c.tooEarly) + var c = openTransf(g, module, "") + result = liftLambdas(g, prc, n, c.tooEarly) #result = n result = processTransf(c, result, prc) liftDefer(c, result) #result = liftLambdas(prc, result) - when useEffectSystem: trackProc(prc, result) - result = liftLocalsIfRequested(prc, result) + when useEffectSystem: trackProc(g, prc, result) + result = liftLocalsIfRequested(prc, result, g.config) if c.needsDestroyPass: #and newDestructors: - result = injectDestructorCalls(prc, result) + result = injectDestructorCalls(g, prc, result) incl(result.flags, nfTransf) #if prc.name.s == "testbody": # echo renderTree(result) -proc transformStmt*(module: PSym, n: PNode): PNode = +proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode = if nfTransf in n.flags: result = n else: - var c = openTransf(module, "") + var c = openTransf(g, module, "") result = processTransf(c, n, module) liftDefer(c, result) #result = liftLambdasForTopLevel(module, result) - when useEffectSystem: trackTopLevelStmt(module, result) + when useEffectSystem: trackTopLevelStmt(g, module, result) #if n.info ?? "temp.nim": # echo renderTree(result, {renderIds}) if c.needsDestroyPass: - result = injectDestructorCalls(module, result) + result = injectDestructorCalls(g, module, result) incl(result.flags, nfTransf) -proc transformExpr*(module: PSym, n: PNode): PNode = +proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode = if nfTransf in n.flags: result = n else: - var c = openTransf(module, "") + var c = openTransf(g, module, "") result = processTransf(c, n, module) liftDefer(c, result) if c.needsDestroyPass: - result = injectDestructorCalls(module, result) + result = injectDestructorCalls(g, module, result) incl(result.flags, nfTransf) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index b0a559d2c2..56ee45b6cb 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -10,7 +10,7 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import ast, passes, msgs, idents, intsets, options +import ast, passes, msgs, idents, intsets, options, modulegraphs const byteExcess* = 128 # we use excess-K for immediates @@ -207,18 +207,18 @@ type errorFlag*: string cache*: IdentCache config*: ConfigRef + graph*: ModuleGraph TPosition* = distinct int PEvalContext* = PCtx -proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx = - let conf = if config != nil: config else: newConfigRef() +proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx = PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "", - cache: cache, config: conf) + cache: cache, config: g.config, graph: g) proc refresh*(c: PCtx, module: PSym) = c.module = module diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index ba37237e82..2c92348a6b 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -9,18 +9,18 @@ import ast, types, msgs, os, streams, options, idents -proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = +proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): string = try: var filename = parentDir(info.toFullPath) / file if not fileExists(filename): - filename = file.findFile + filename = findFile(conf, file) result = readFile(filename) # we produce a fake include statement for every slurped filename, so that # the module dependencies are accurate: appendToModule(module, newNode(nkIncludeStmt, info, @[ newStrNode(nkStrLit, filename)])) except IOError: - localError(info, errCannotOpenFile, file) + localError(conf, info, "cannot open file: " & file) result = "" proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode = @@ -271,7 +271,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; of tyOr: result = mapTypeToBracket("or", mOr, t, info) of tyNot: result = mapTypeToBracket("not", mNot, t, info) of tyAnything: result = atomicType("anything", mNone) - of tyInferred: internalAssert false + of tyInferred: assert false of tyStatic, tyFromExpr: if inst: if t.n != nil: result = t.n.copyTree @@ -281,7 +281,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; result.add atomicType("static", mNone) if t.n != nil: result.add t.n.copyTree - of tyUnused, tyOptAsRef: internalError("mapTypeToAstX") + of tyUnused, tyOptAsRef: assert(false, "mapTypeToAstX") proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode = result = mapTypeToAstX(t, info, false, true) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 7f91e63db9..7ac3b5cf75 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -120,7 +120,7 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) = c.code.add(ins) c.debug.add(n.info) else: - localError(n.info, errGenerated, + localError(c.config, n.info, "VM: immediate value does not fit into an int8") proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) = @@ -137,7 +137,7 @@ proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) = c.code.add(ins) c.debug.add(n.info) else: - localError(n.info, errGenerated, + localError(c.config, n.info, "VM: immediate value does not fit into an int16") proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition = @@ -151,7 +151,7 @@ proc genLabel(c: PCtx): TPosition = proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) = let dist = p.int - c.code.len - internalAssert(-0x7fff < dist and dist < 0x7fff) + internalAssert(c.config, -0x7fff < dist and dist < 0x7fff) gABx(c, n, opcJmpBack, 0, dist) proc patch(c: PCtx, p: TPosition) = @@ -159,7 +159,7 @@ proc patch(c: PCtx, p: TPosition) = let p = p.int let diff = c.code.len - p #c.jumpTargets.incl(c.code.len) - internalAssert(-0x7fff < diff and diff < 0x7fff) + internalAssert(c.config, -0x7fff < diff and diff < 0x7fff) let oldInstr = c.code[p] # opcode and regA stay the same: c.code[p] = ((oldInstr.uint32 and 0xffff'u32).uint32 or @@ -201,7 +201,7 @@ proc getTemp(cc: PCtx; tt: PType): TRegister = c.slots[i] = (inUse: true, kind: k) return TRegister(i) if c.maxSlots >= high(TRegister): - globalError(cc.bestEffort, "VM problem: too many registers required") + globalError(cc.config, cc.bestEffort, "VM problem: too many registers required") result = TRegister(c.maxSlots) c.slots[c.maxSlots] = (inUse: true, kind: k) inc c.maxSlots @@ -223,7 +223,7 @@ proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister = for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind) return if c.maxSlots+n >= high(TRegister): - globalError(cc.bestEffort, "VM problem: too many registers required") + globalError(cc.config, cc.bestEffort, "VM problem: too many registers required") result = TRegister(c.maxSlots) inc c.maxSlots, n for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind) @@ -251,7 +251,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) = var d: TDest = dest gen(c, n, d, flags) - #internalAssert d == dest # issue #7407 + #internalAssert c.config, d == dest # issue #7407 proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) = var tmp: TDest = -1 @@ -261,7 +261,7 @@ proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) = proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister = var tmp: TDest = -1 gen(c, n, tmp, flags) - #internalAssert tmp >= 0 # 'nim check' does not like this internalAssert. + #internalAssert c.config, tmp >= 0 # 'nim check' does not like this internalAssert. if tmp >= 0: result = TRegister(tmp) @@ -320,7 +320,7 @@ proc genBreak(c: PCtx; n: PNode) = if c.prc.blocks[i].label == n.sons[0].sym: c.prc.blocks[i].fixups.add L1 return - globalError(n.info, errGenerated, "VM problem: cannot find 'break' target") + globalError(c.config, n.info, "VM problem: cannot find 'break' target") else: c.prc.blocks[c.prc.blocks.high].fixups.add L1 @@ -378,7 +378,7 @@ proc rawGenLiteral(c: PCtx; n: PNode): int = #assert(n.kind != nkCall) n.flags.incl nfAllConst c.constants.add n.canonValue - internalAssert result < 0x7fff + internalAssert c.config, result < 0x7fff proc sameConstant*(a, b: PNode): bool = result = false @@ -405,10 +405,10 @@ proc genLiteral(c: PCtx; n: PNode): int = if sameConstant(c.constants[i], n): return i result = rawGenLiteral(c, n) -proc unused(n: PNode; x: TDest) {.inline.} = +proc unused(c: PCtx; n: PNode; x: TDest) {.inline.} = if x >= 0: #debug(n) - globalError(n.info, "not unused") + globalError(c.config, n.info, "not unused") proc genCase(c: PCtx; n: PNode; dest: var TDest) = # if (!expr1) goto L1; @@ -424,7 +424,7 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) = if not isEmptyType(n.typ): if dest < 0: dest = getTemp(c, n.typ) else: - unused(n, dest) + unused(c, n, dest) var endings: seq[TPosition] = @[] withTemp(tmp, n.sons[0].typ): c.gen(n.sons[0], tmp) @@ -451,7 +451,7 @@ proc genType(c: PCtx; typ: PType): int = if sameType(t, typ): return i result = c.types.len c.types.add(typ) - internalAssert(result <= 0x7fff) + internalAssert(c.config, result <= 0x7fff) proc genTry(c: PCtx; n: PNode; dest: var TDest) = if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ) @@ -525,7 +525,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) = var r: TRegister = x+i c.gen(n.sons[i], r) if i >= fntyp.len: - internalAssert tfVarargs in fntyp.flags + internalAssert c.config, tfVarargs in fntyp.flags c.gABx(n, opcSetType, r, c.genType(n.sons[i].typ)) if dest < 0: c.gABC(n, opcIndCall, 0, x, n.len) @@ -540,12 +540,12 @@ proc needsAsgnPatch(n: PNode): bool = n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal) -proc genField(n: PNode): TRegister = +proc genField(c: PCtx; n: PNode): TRegister = if n.kind != nkSym or n.sym.kind != skField: - globalError(n.info, "no field symbol") + globalError(c.config, n.info, "no field symbol") let s = n.sym if s.position > high(result): - globalError(n.info, + globalError(c.config, n.info, "too large offset! cannot generate code for: " & s.name.s) result = s.position @@ -572,7 +572,7 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess}) - let idx = genField(left.sons[1]) + let idx = genField(c, left.sons[1]) c.gABC(left, opcWrObj, dest, idx, value) c.freeTemp(dest) of nkDerefExpr, nkHiddenDeref: @@ -779,7 +779,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) = let tmp3 = c.getTemp(n.sons[1].typ) if dest < 0: dest = c.getTemp(n[0].typ) proc mkIntLit(ival: int): int = - result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(tyInt))) + result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(c.graph, n.info, tyInt))) if src.kind in unsignedIntegers and dst.kind in signedIntegers: # cast unsigned to signed integer of same size # signedVal = (unsignedVal xor offset) -% offset @@ -802,7 +802,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) = c.freeTemp(tmp2) c.freeTemp(tmp3) else: - globalError(n.info, errGenerated, "VM is only allowed to 'cast' between integers of same size") + globalError(c.config, n.info, "VM is only allowed to 'cast' between integers of same size") proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = case m @@ -818,7 +818,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mSucc, mAddI: c.genAddSubInt(n, dest, opcAddInt) of mInc, mDec: - unused(n, dest) + unused(c, n, dest) let opc = if m == mInc: opcAddInt else: opcSubInt let d = c.genx(n.sons[1]) if n.sons[2].isInt8Lit: @@ -832,10 +832,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.freeTemp(d) of mOrd, mChr, mArrToSeq: c.gen(n.sons[1], dest) of mNew, mNewFinalize: - unused(n, dest) + unused(c, n, dest) c.genNew(n) of mNewSeq: - unused(n, dest) + unused(c, n, dest) c.genNewSeq(n) of mNewSeqOfCap: c.genNewSeqOfCap(n, dest) of mNewString: @@ -855,7 +855,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mLengthStr, mXLenStr: genUnaryABI(c, n, dest, opcLenStr) of mIncl, mExcl: - unused(n, dest) + unused(c, n, dest) var d = c.genx(n.sons[1]) var tmp = c.genx(n.sons[2]) c.genSetType(n.sons[1], d) @@ -952,19 +952,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mInSet: genBinarySet(c, n, dest, opcContainsSet) of mRepr: genUnaryABC(c, n, dest, opcRepr) of mExit: - unused(n, dest) + unused(c, n, dest) var tmp = c.genx(n.sons[1]) c.gABC(n, opcQuit, tmp) c.freeTemp(tmp) of mSetLengthStr, mSetLengthSeq: - unused(n, dest) + unused(c, n, dest) var d = c.genx(n.sons[1]) var tmp = c.genx(n.sons[2]) c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp) c.genAsgnPatch(n.sons[1], d) c.freeTemp(tmp) of mSwap: - unused(n, dest) + unused(c, n, dest) c.gen(lowerSwap(n, if c.prc == nil: c.module else: c.prc.sym)) of mIsNil: genUnaryABC(c, n, dest, opcIsNil) of mCopyStr: @@ -996,7 +996,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = # skip 'nkHiddenAddr': let d2AsNode = n.sons[2].sons[0] if needsAsgnPatch(d2AsNode): - d2 = c.getTemp(getSysType(tyFloat)) + d2 = c.getTemp(getSysType(c.graph, n.info, tyFloat)) else: d2 = c.genx(d2AsNode) var @@ -1009,13 +1009,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.genAsgnPatch(d2AsNode, d2) c.freeTemp(d2) of mReset: - unused(n, dest) + unused(c, n, dest) var d = c.genx(n.sons[1]) c.gABC(n, opcReset, d) of mOf, mIs: if dest < 0: dest = c.getTemp(n.typ) var tmp = c.genx(n.sons[1]) - var idx = c.getTemp(getSysType(tyInt)) + var idx = c.getTemp(getSysType(c.graph, n.info, tyInt)) var typ = n.sons[2].typ if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc}) c.gABx(n, opcLdImmInt, idx, c.genType(typ)) @@ -1023,7 +1023,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.freeTemp(tmp) c.freeTemp(idx) of mSizeOf: - globalError(n.info, errCannotInterpretNodeX, renderTree(n)) + globalError(c.config, n.info, "cannot run in the VM: " & renderTree(n)) of mHigh: if dest < 0: dest = c.getTemp(n.typ) let tmp = c.genx(n.sons[1]) @@ -1034,23 +1034,23 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.gABI(n, opcLenSeq, dest, tmp, 1) c.freeTemp(tmp) of mEcho: - unused(n, dest) + unused(c, n, dest) let n = n[1].skipConv let x = c.getTempRange(n.len, slotTempUnknown) - internalAssert n.kind == nkBracket + internalAssert c.config, n.kind == nkBracket for i in 0..= high(TRegister): - globalError(v.info, "cannot generate code; too many registers required") + globalError(c.config, v.info, "cannot generate code; too many registers required") v.position = c.prc.maxSlots c.prc.slots[v.position] = (inUse: true, kind: if v.kind == skLet: slotFixedLet else: slotFixedVar) inc c.prc.maxSlots -proc cannotEval(n: PNode) {.noinline.} = - globalError(n.info, errGenerated, "cannot evaluate at compile time: " & +proc cannotEval(c: PCtx; n: PNode) {.noinline.} = + globalError(c.config, n.info, "cannot evaluate at compile time: " & n.renderTree) proc isOwnedBy(a, b: PSym): bool = @@ -1333,10 +1333,10 @@ proc checkCanEval(c: PCtx; n: PNode) = 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 and c.mode != emRepl: - cannotEval(n) + cannotEval(c, n) elif s.kind in {skProc, skFunc, skConverter, skMethod, skIterator} and sfForward in s.flags: - cannotEval(n) + cannotEval(c, n) proc isTemp(c: PCtx; dest: TDest): bool = result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown @@ -1378,7 +1378,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess}) - let idx = genField(left.sons[1]) + let idx = genField(c, left.sons[1]) let tmp = c.genx(ri) c.preventFalseAlias(left, opcWrObj, dest, idx, tmp) c.freeTemp(tmp) @@ -1398,7 +1398,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = c.freeTemp(val) else: if s.kind == skForVar: c.setSlot s - internalAssert s.position > 0 or (s.position == 0 and + internalAssert c.config, s.position > 0 or (s.position == 0 and s.kind in {skParam,skResult}) var dest: TRegister = s.position + ord(s.kind == skParam) assert le.typ != nil @@ -1424,15 +1424,15 @@ proc importcSym(c: PCtx; info: TLineInfo; s: PSym) = c.globals.add(importcSymbol(s)) s.position = c.globals.len else: - localError(info, errGenerated, "VM is not allowed to 'importc'") + localError(c.config, info, "VM is not allowed to 'importc'") else: - localError(info, errGenerated, + localError(c.config, info, "cannot 'importc' variable at compile time") -proc getNullValue*(typ: PType, info: TLineInfo): PNode +proc getNullValue*(typ: PType, info: TLineInfo; conf: ConfigRef): PNode proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = - c.globals.add(getNullValue(s.typ, n.info)) + c.globals.add(getNullValue(s.typ, n.info, c.config)) s.position = c.globals.len # This is rather hard to support, due to the laziness of the VM code # generator. See tests/compile/tmacro2 for why this is necessary: @@ -1451,7 +1451,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = if sfCompileTime in s.flags or c.mode == emRepl: discard elif s.position == 0: - cannotEval(n) + cannotEval(c, n) if s.position == 0: if sfImportc in s.flags: c.importcSym(n.info, s) else: genGlobalInit(c, n, s) @@ -1472,13 +1472,13 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = s.kind in {skParam,skResult}): if dest < 0: dest = s.position + ord(s.kind == skParam) - internalAssert(c.prc.slots[dest].kind < slotSomeTemp) + internalAssert(c.config, c.prc.slots[dest].kind < slotSomeTemp) else: # we need to generate an assignment: genAsgn(c, dest, n, c.prc.slots[dest].kind >= slotSomeTemp) else: # see tests/t99bott for an example that triggers it: - cannotEval(n) + cannotEval(c, n) template needsRegLoad(): untyped = gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar, tyLent})) @@ -1502,7 +1502,7 @@ proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = let a = c.genx(n.sons[0], flags) - let b = genField(n.sons[1]) + let b = genField(c, n.sons[1]) if dest < 0: dest = c.getTemp(n.typ) if needsRegLoad(): var cc = c.getTemp(n.typ) @@ -1526,22 +1526,22 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = else: genArrAccess2(c, n, dest, opcLdArr, flags) -proc getNullValueAux(obj: PNode, result: PNode) = +proc getNullValueAux(obj: PNode, result: PNode; conf: ConfigRef) = case obj.kind of nkRecList: - for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result) + for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result, conf) of nkRecCase: - getNullValueAux(obj.sons[0], result) + getNullValueAux(obj.sons[0], result, conf) for i in countup(1, sonsLen(obj) - 1): - getNullValueAux(lastSon(obj.sons[i]), result) + getNullValueAux(lastSon(obj.sons[i]), result, conf) of nkSym: let field = newNodeI(nkExprColonExpr, result.info) field.add(obj) - field.add(getNullValue(obj.sym.typ, result.info)) + field.add(getNullValue(obj.sym.typ, result.info, conf)) addSon(result, field) - else: globalError(result.info, "cannot create null element for: " & $obj) + else: globalError(conf, result.info, "cannot create null element for: " & $obj) -proc getNullValue(typ: PType, info: TLineInfo): PNode = +proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = var t = skipTypes(typ, abstractRange-{tyTypeDesc}) result = emptyNode case t.kind @@ -1570,17 +1570,17 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = # initialize inherited fields: var base = t.sons[0] while base != nil: - getNullValueAux(skipTypes(base, skipPtrs).n, result) + getNullValueAux(skipTypes(base, skipPtrs).n, result, conf) base = base.sons[0] - getNullValueAux(t.n, result) + getNullValueAux(t.n, result, conf) of tyArray: result = newNodeIT(nkBracket, info, t) for i in countup(0, int(lengthOrd(t)) - 1): - addSon(result, getNullValue(elemType(t), info)) + addSon(result, getNullValue(elemType(t), info, conf)) of tyTuple: result = newNodeIT(nkTupleConstr, info, t) for i in countup(0, sonsLen(t) - 1): - addSon(result, getNullValue(t.sons[i], info)) + addSon(result, getNullValue(t.sons[i], info, conf)) of tySet: result = newNodeIT(nkCurly, info, t) of tyOpt: @@ -1588,7 +1588,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = of tySequence: result = newNodeIT(nkBracket, info, t) else: - globalError(info, "cannot create null element for: " & $t.kind) + globalError(conf, info, "cannot create null element for: " & $t.kind) proc ldNullOpcode(t: PType): TOpcode = assert t != nil @@ -1602,7 +1602,7 @@ proc genVarSection(c: PCtx; n: PNode) = for i in 0 .. a.len-3: if not a[i].sym.isGlobal: setSlot(c, a[i].sym) checkCanEval(c, a[i]) - c.gen(lowerTupleUnpacking(a, c.getOwner)) + c.gen(lowerTupleUnpacking(c.graph, a, c.getOwner)) elif a.sons[0].kind == nkSym: let s = a.sons[0].sym checkCanEval(c, a.sons[0]) @@ -1610,7 +1610,7 @@ proc genVarSection(c: PCtx; n: PNode) = if s.position == 0: if sfImportc in s.flags: c.importcSym(a.info, s) else: - let sa = getNullValue(s.typ, a.info) + let sa = getNullValue(s.typ, a.info, c.config) #if s.ast.isNil: getNullValue(s.typ, a.info) #else: canonValue(s.ast) assert sa.kind != nkCall @@ -1652,7 +1652,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) = if dest < 0: dest = c.getTemp(n.typ) c.gABx(n, opcLdNull, dest, c.genType(n.typ)) - let intType = getSysType(tyInt) + let intType = getSysType(c.graph, n.info, tyInt) let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc}) if seqType.kind == tySequence: var tmp = c.getTemp(intType) @@ -1696,13 +1696,13 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) = for i in 1..= 0: - globalError(n.info, errGenerated, "VM problem: dest register is set") + globalError(c.config, n.info, "VM problem: dest register is set") proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int = c.removeLastEof @@ -1924,7 +1924,7 @@ proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int = c.gen(n, d) if d < 0: if requiresValue: - globalError(n.info, errGenerated, "VM problem: dest register is not set") + globalError(c.config, n.info, "VM problem: dest register is not set") d = 0 c.gABC(n, opcEof, d) @@ -1939,7 +1939,7 @@ proc genParams(c: PCtx; params: PNode) = c.prc.maxSlots = max(params.len, 1) proc finalJumpTarget(c: PCtx; pc, diff: int) = - internalAssert(-0x7fff < diff and diff < 0x7fff) + internalAssert(c.config, -0x7fff < diff and diff < 0x7fff) let oldInstr = c.code[pc] # opcode and regA stay the same: c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index d769094432..f38be7c290 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -9,7 +9,8 @@ ## Implements marshaling for the VM. -import streams, json, intsets, tables, ast, astalgo, idents, types, msgs +import streams, json, intsets, tables, ast, astalgo, idents, types, msgs, + options proc ptrToInt(x: PNode): int {.inline.} = result = cast[int](x) # don't skip alignment @@ -28,37 +29,38 @@ proc getField(n: PNode; position: int): PSym = of nkOfBranch, nkElse: result = getField(lastSon(n.sons[i]), position) if result != nil: return - else: internalError(n.info, "getField(record case branch)") + else: discard of nkSym: if n.sym.position == position: result = n.sym else: discard -proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) +proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; conf: ConfigRef) -proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) = - internalAssert x.kind == nkObjConstr +proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet; conf: ConfigRef) = + assert x.kind == nkObjConstr let start = 1 for i in countup(start, sonsLen(x) - 1): if i > start: s.add(", ") var it = x.sons[i] if it.kind == nkExprColonExpr: - internalAssert it.sons[0].kind == nkSym - let field = it.sons[0].sym - s.add(escapeJson(field.name.s)) - s.add(": ") - storeAny(s, field.typ, it.sons[1], stored) + if it.sons[0].kind == nkSym: + let field = it.sons[0].sym + s.add(escapeJson(field.name.s)) + s.add(": ") + storeAny(s, field.typ, it.sons[1], stored, conf) elif typ.n != nil: let field = getField(typ.n, i) s.add(escapeJson(field.name.s)) s.add(": ") - storeAny(s, field.typ, it, stored) + storeAny(s, field.typ, it, stored, conf) proc skipColon*(n: PNode): PNode = result = n if n.kind == nkExprColonExpr: result = n.sons[1] -proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = +proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; + conf: ConfigRef) = case t.kind of tyNone: assert false of tyBool: s.add($(a.intVal != 0)) @@ -74,7 +76,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = s.add("[") for i in 0 .. a.len-1: if i > 0: s.add(", ") - storeAny(s, t.elemType, a[i], stored) + storeAny(s, t.elemType, a[i], stored, conf) s.add("]") of tyTuple: s.add("{") @@ -82,11 +84,11 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = if i > 0: s.add(", ") s.add("\"Field" & $i) s.add("\": ") - storeAny(s, t.sons[i], a[i].skipColon, stored) + storeAny(s, t.sons[i], a[i].skipColon, stored, conf) s.add("}") of tyObject: s.add("{") - storeObj(s, t, a, stored) + storeObj(s, t, a, stored, conf) s.add("}") of tySet: s.add("[") @@ -94,15 +96,16 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = if i > 0: s.add(", ") if a[i].kind == nkRange: var x = copyNode(a[i][0]) - storeAny(s, t.lastSon, x, stored) + storeAny(s, t.lastSon, x, stored, conf) while x.intVal+1 <= a[i][1].intVal: s.add(", ") - storeAny(s, t.lastSon, x, stored) + storeAny(s, t.lastSon, x, stored, conf) inc x.intVal else: - storeAny(s, t.lastSon, a[i], stored) + storeAny(s, t.lastSon, a[i], stored, conf) s.add("]") - of tyRange, tyGenericInst, tyAlias, tySink: storeAny(s, t.lastSon, a, stored) + of tyRange, tyGenericInst, tyAlias, tySink: + storeAny(s, t.lastSon, a, stored, conf) of tyEnum: # we need a slow linear search because of enums with holes: for e in items(t.n): @@ -121,7 +124,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = s.add("[") s.add($x.ptrToInt) s.add(", ") - storeAny(s, t.lastSon, a, stored) + storeAny(s, t.lastSon, a, stored, conf) s.add("]") of tyString, tyCString: if a.kind == nkNilLit or a.strVal.isNil: s.add("null") @@ -129,14 +132,15 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal) of tyFloat..tyFloat128: s.add($a.floatVal) else: - internalError a.info, "cannot marshal at compile-time " & t.typeToString + internalError conf, a.info, "cannot marshal at compile-time " & t.typeToString -proc storeAny*(s: var string; t: PType; a: PNode) = +proc storeAny*(s: var string; t: PType; a: PNode; conf: ConfigRef) = var stored = initIntSet() - storeAny(s, t, a, stored) + storeAny(s, t, a, stored, conf) proc loadAny(p: var JsonParser, t: PType, - tab: var Table[BiggestInt, PNode]): PNode = + tab: var Table[BiggestInt, PNode]; + conf: ConfigRef): PNode = case t.kind of tyNone: assert false of tyBool: @@ -170,7 +174,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkBracket) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.elemType, tab) + result.add loadAny(p, t.elemType, tab, conf) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "']' end of array expected") of tySequence: @@ -182,7 +186,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkBracket) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.elemType, tab) + result.add loadAny(p, t.elemType, tab, conf) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "") else: @@ -198,7 +202,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) if i >= t.len: raiseParseErr(p, "too many fields to tuple type " & typeToString(t)) - result.add loadAny(p, t.sons[i], tab) + result.add loadAny(p, t.sons[i], tab, conf) inc i if p.kind == jsonObjectEnd: next(p) else: raiseParseErr(p, "'}' end of object expected") @@ -220,7 +224,7 @@ proc loadAny(p: var JsonParser, t: PType, setLen(result.sons, pos + 1) let fieldNode = newNode(nkExprColonExpr) fieldNode.addSon(newSymNode(newSym(skField, ident, nil, unknownLineInfo()))) - fieldNode.addSon(loadAny(p, field.typ, tab)) + fieldNode.addSon(loadAny(p, field.typ, tab, conf)) result.sons[pos] = fieldNode if p.kind == jsonObjectEnd: next(p) else: raiseParseErr(p, "'}' end of object expected") @@ -229,7 +233,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkCurly) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.lastSon, tab) + result.add loadAny(p, t.lastSon, tab, conf) next(p) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "']' end of array expected") @@ -248,7 +252,7 @@ proc loadAny(p: var JsonParser, t: PType, if p.kind == jsonInt: let idx = p.getInt next(p) - result = loadAny(p, t.lastSon, tab) + result = loadAny(p, t.lastSon, tab, conf) tab[idx] = result else: raiseParseErr(p, "index for ref type expected") if p.kind == jsonArrayEnd: next(p) @@ -275,14 +279,15 @@ proc loadAny(p: var JsonParser, t: PType, next(p) return raiseParseErr(p, "float expected") - of tyRange, tyGenericInst, tyAlias, tySink: result = loadAny(p, t.lastSon, tab) + of tyRange, tyGenericInst, tyAlias, tySink: + result = loadAny(p, t.lastSon, tab, conf) else: - internalError "cannot marshal at compile-time " & t.typeToString + internalError conf, "cannot marshal at compile-time " & t.typeToString -proc loadAny*(s: string; t: PType): PNode = +proc loadAny*(s: string; t: PType; conf: ConfigRef): PNode = var tab = initTable[BiggestInt, PNode]() var p: JsonParser open(p, newStringStream(s), "unknown file") next(p) - result = loadAny(p, t, tab) + result = loadAny(p, t, tab, conf) close(p) From 05724645f815bea56a65bd78a9f2228811573413 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 11:58:44 +0200 Subject: [PATCH 187/214] more modules compile again --- compiler/aliases.nim | 4 +- compiler/evaltempl.nim | 28 +++-- compiler/guards.nim | 4 +- compiler/hlo.nim | 2 +- compiler/patterns.nim | 4 +- compiler/plugins/itersgen.nim | 10 +- compiler/sem.nim | 51 +++++---- compiler/semmacrosanity.nim | 36 +++--- compiler/semparallel.nim | 128 +++++++++++---------- compiler/vm.nim | 210 ++++++++++++++++++---------------- compiler/vmdef.nim | 1 + compiler/vmops.nim | 18 ++- 12 files changed, 260 insertions(+), 236 deletions(-) diff --git a/compiler/aliases.nim b/compiler/aliases.nim index 490ac987a7..f79210dd73 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -34,10 +34,10 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult = of nkOfBranch, nkElse: result = isPartOfAux(lastSon(n.sons[i]), b, marker) if result == arYes: return - else: internalError("isPartOfAux(record case branch)") + else: discard "isPartOfAux(record case branch)" of nkSym: result = isPartOfAux(n.sym.typ, b, marker) - else: internalError(n.info, "isPartOfAux()") + else: discard proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult = result = arNo diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index fbb7eb2e6e..2133701e66 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -14,11 +14,12 @@ import rodread type - TemplCtx {.pure, final.} = object + TemplCtx = object owner, genSymOwner: PSym instLines: bool # use the instantiation lines numbers mapping: TIdTable # every gensym'ed symbol needs to be mapped to some # new symbol + config: ConfigRef proc copyNode(ctx: TemplCtx, a, b: PNode): PNode = result = copyNode(a) @@ -42,7 +43,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam: handleParam actual.sons[s.owner.typ.len + s.position - 1] else: - internalAssert sfGenSym in s.flags or s.kind == skType + internalAssert c.config, sfGenSym in s.flags or s.kind == skType var x = PSym(idTableGet(c.mapping, s)) if x == nil: x = copySym(s, false) @@ -59,7 +60,12 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = evalTemplateAux(templ.sons[i], actual, c, res) result.add res -proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = +const + errWrongNumberOfArguments = "wrong number of arguments" + errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters" + errTemplateInstantiationTooNested = "template instantiation too nested" + +proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode = # if the template has zero arguments, it can be called without ``()`` # `n` is then a nkSym or something similar var totalParams = case n.kind @@ -82,10 +88,10 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = if givenRegularParams < 0: givenRegularParams = 0 if totalParams > expectedRegularParams + genericParams: - globalError(n.info, errWrongNumberOfArguments) + globalError(conf, n.info, errWrongNumberOfArguments) if totalParams < genericParams: - globalError(n.info, errMissingGenericParamsForTemplate, + globalError(conf, n.info, errMissingGenericParamsForTemplate % n.renderTree) result = newNodeI(nkArgList, n.info) @@ -97,7 +103,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = for i in givenRegularParams+1 .. expectedRegularParams: let default = s.typ.n.sons[i].sym.ast if default.isNil or default.kind == nkEmpty: - localError(n.info, errWrongNumberOfArguments) + localError(conf, n.info, errWrongNumberOfArguments) addSon(result, ast.emptyNode) else: addSon(result, default.copyTree) @@ -132,17 +138,19 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = result.add res result.typ = res.typ -proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = +proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; + conf: ConfigRef; fromHlo=false): PNode = inc(evalTemplateCounter) if evalTemplateCounter > evalTemplateLimit: - globalError(n.info, errTemplateInstantiationTooNested) + globalError(conf, n.info, errTemplateInstantiationTooNested) result = n # replace each param by the corresponding node: - var args = evalTemplateArgs(n, tmpl, fromHlo) + var args = evalTemplateArgs(n, tmpl, conf, fromHlo) var ctx: TemplCtx ctx.owner = tmpl ctx.genSymOwner = genSymOwner + ctx.config = conf initIdTable(ctx.mapping) let body = tmpl.getBody @@ -151,7 +159,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = evalTemplateAux(body, args, ctx, result) if result.len == 1: result = result.sons[0] else: - localError(result.info, errIllFormedAstX, + localError(conf, result.info, "illformed AST: " & renderTree(result, {renderNoComments})) else: result = copyNode(body) diff --git a/compiler/guards.nim b/compiler/guards.nim index 68f979a9f4..d39ea799bd 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -330,8 +330,8 @@ proc canon*(n: PNode; o: Operators): PNode = result.sons[2] = y[1] else: discard -#proc `+@`*(a: PNode; b: BiggestInt): PNode = -# canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a) +proc buildAdd*(a: PNode; b: BiggestInt; o: Operators): PNode = + canon(if b != 0: o.opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a, o) proc usefulFact(n: PNode; o: Operators): PNode = case n.getMagic diff --git a/compiler/hlo.nim b/compiler/hlo.nim index c4288c3626..3e19be6e90 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -12,7 +12,7 @@ proc hlo(c: PContext, n: PNode): PNode proc evalPattern(c: PContext, n, orig: PNode): PNode = - internalAssert n.kind == nkCall and n.sons[0].kind == nkSym + internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym # we need to ensure that the resulting AST is semchecked. However, it's # aweful to semcheck before macro invocation, so we don't and treat # templates and macros as immediate in this context. diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 31b76743ed..5409a48112 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -150,7 +150,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool = of "*": result = matchNested(c, p, n, rpn=false) of "**": result = matchNested(c, p, n, rpn=true) of "~": result = not matches(c, p.sons[1], n) - else: internalError(p.info, "invalid pattern") + else: doAssert(false, "invalid pattern") # template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) = # add(a, b) elif p.kind == nkCurlyExpr: @@ -289,7 +289,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = # constraint not fulfilled: if not ok: return nil - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) if ctx.subMatch: assert m.len == 3 m.sons[1] = result diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim index dbc47e11eb..ebb65dd4ad 100644 --- a/compiler/plugins/itersgen.nim +++ b/compiler/plugins/itersgen.nim @@ -17,21 +17,21 @@ proc iterToProcImpl(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) let iter = n[1] if iter.kind != nkSym or iter.sym.kind != skIterator: - localError(iter.info, "first argument needs to be an iterator") + localError(c.config, iter.info, "first argument needs to be an iterator") return if n[2].typ.isNil: - localError(n[2].info, "second argument needs to be a type") + localError(c.config, n[2].info, "second argument needs to be a type") return if n[3].kind != nkIdent: - localError(n[3].info, "third argument needs to be an identifier") + localError(c.config, n[3].info, "third argument needs to be an identifier") return let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst}) if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject: - localError(n[2].info, + localError(c.config, n[2].info, "type must be a non-generic ref|ptr to object with state field") return - let body = liftIterToProc(iter.sym, iter.sym.getBody, t) + let body = liftIterToProc(c.graph, iter.sym, iter.sym.getBody, t) let prc = newSym(skProc, n[3].ident, iter.sym.owner, iter.sym.info) prc.typ = copyType(iter.sym.typ, prc, false) diff --git a/compiler/sem.nim b/compiler/sem.nim index d8e5b7f205..ae32ecb8a0 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -71,7 +71,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode; proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = if arg.typ.isNil: - localError(arg.info, errExprXHasNoType, + localError(c.config, arg.info, "expression has no type: " & renderTree(arg, {renderNoComments})) # error correction: result = copyTree(arg) @@ -79,7 +79,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = else: result = indexTypesMatch(c, formal, arg.typ, arg) if result == nil: - typeMismatch(info, formal, arg.typ) + typeMismatch(c.config, info, formal, arg.typ) # error correction: result = copyTree(arg) result.typ = formal @@ -180,7 +180,7 @@ proc commonType*(x: PType, y: PNode): PType = commonType(x, y.typ) proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = - result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info) when defined(nimsuggest): suggestDecl(c, n, result) @@ -192,7 +192,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # and sfGenSym in n.sym.flags: result = n.sym if result.kind != kind: - localError(n.info, "cannot use symbol of kind '" & + localError(c.config, n.info, "cannot use symbol of kind '" & $result.kind & "' as a '" & $kind & "'") if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}: # declarative context, so produce a fresh gensym: @@ -204,7 +204,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # template; we must fix it here: see #909 result.owner = getCurrOwner(c) else: - result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info) #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: # incl(result.flags, sfGlobal) when defined(nimsuggest): @@ -216,20 +216,20 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym -proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind; +proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind; flags: TTypeAllowedFlags = {}) = let t = typeAllowed(typ, kind, flags) if t != nil: if t == typ: - localError(info, "invalid type: '" & typeToString(typ) & + localError(conf, info, "invalid type: '" & typeToString(typ) & "' for " & substr($kind, 2).toLowerAscii) else: - localError(info, "invalid type: '" & typeToString(t) & + localError(conf, info, "invalid type: '" & typeToString(t) & "' in this context: '" & typeToString(typ) & "' for " & substr($kind, 2).toLowerAscii) proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} = - typeAllowedCheck(typ.n.info, typ, skProc) + typeAllowedCheck(c.config, typ.n.info, typ, skProc) proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode @@ -282,10 +282,10 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode = result = evaluated let expectedType = eOrig.typ.skipTypes({tyStatic}) if hasCycle(result): - globalError(eOrig.info, "the resulting AST is cyclic and cannot be processed further") + globalError(c.config, eOrig.info, "the resulting AST is cyclic and cannot be processed further") result = errorNode(c, eOrig) else: - semmacrosanity.annotateType(result, expectedType) + semmacrosanity.annotateType(result, expectedType, c.config) else: result = semExprWithType(c, evaluated) #result = fitNode(c, e.typ, result) inlined with special case: @@ -302,18 +302,18 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = var e = semExprWithType(c, n) if e == nil: return - result = getConstExpr(c.module, e) + result = getConstExpr(c.module, e, c.graph) if result != nil: return - let oldErrorCount = msgs.gErrorCounter - let oldErrorMax = msgs.gErrorMax + let oldErrorCount = c.config.errorCounter + let oldErrorMax = c.config.errorMax let oldErrorOutputs = errorOutputs errorOutputs = {} - msgs.gErrorMax = high(int) + c.config.errorMax = high(int) try: - result = evalConstExpr(c.module, c.cache, c.graph.config, e) + result = evalConstExpr(c.module, c.cache, c.graph, e) if result == nil or result.kind == nkEmpty: result = nil else: @@ -322,26 +322,29 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = except ERecoverableError: result = nil - msgs.gErrorCounter = oldErrorCount - msgs.gErrorMax = oldErrorMax + c.config.errorCounter = oldErrorCount + c.config.errorMax = oldErrorMax errorOutputs = oldErrorOutputs +const + errConstExprExpected = "constant expression expected" + proc semConstExpr(c: PContext, n: PNode): PNode = var e = semExprWithType(c, n) if e == nil: - localError(n.info, errConstExprExpected) + localError(c.config, n.info, errConstExprExpected) return n - result = getConstExpr(c.module, e) + result = getConstExpr(c.module, e, c.graph) if result == nil: #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) - result = evalConstExpr(c.module, c.cache, c.graph.config, e) + result = evalConstExpr(c.module, c.cache, c.graph, e) if result == nil or result.kind == nkEmpty: if e.info != n.info: pushInfoContext(n.info) - localError(e.info, errConstExprExpected) + localError(c.config, e.info, errConstExprExpected) popInfoContext() else: - localError(e.info, errConstExprExpected) + localError(c.config, e.info, errConstExprExpected) # error correction: result = e else: @@ -356,7 +359,7 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode = else: result = semExprWithType(c, n, flags) if efPreferStatic in flags: - var evaluated = getConstExpr(c.module, result) + var evaluated = getConstExpr(c.module, result, c.graph) if evaluated != nil: return evaluated evaluated = evalAtCompileTime(c, result) if evaluated != nil: return evaluated diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index f6df674412..02c56c0354 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -10,7 +10,7 @@ ## Implements type sanity checking for ASTs resulting from macros. Lots of ## room for improvement here. -import ast, astalgo, msgs, types +import ast, astalgo, msgs, types, options proc ithField(n: PNode, field: var int): PSym = result = nil @@ -20,7 +20,7 @@ proc ithField(n: PNode, field: var int): PSym = result = ithField(n.sons[i], field) if result != nil: return of nkRecCase: - if n.sons[0].kind != nkSym: internalError(n.info, "ithField") + if n.sons[0].kind != nkSym: return result = ithField(n.sons[0], field) if result != nil: return for i in countup(1, sonsLen(n) - 1): @@ -28,13 +28,13 @@ proc ithField(n: PNode, field: var int): PSym = of nkOfBranch, nkElse: result = ithField(lastSon(n.sons[i]), field) if result != nil: return - else: internalError(n.info, "ithField(record case branch)") + else: discard of nkSym: if field == 0: result = n.sym else: dec(field) else: discard -proc annotateType*(n: PNode, t: PType) = +proc annotateType*(n: PNode, t: PType; conf: ConfigRef) = let x = t.skipTypes(abstractInst+{tyRange}) # Note: x can be unequal to t and we need to be careful to use 't' # to not to skip tyGenericInst @@ -46,50 +46,50 @@ proc annotateType*(n: PNode, t: PType) = var j = i-1 let field = x.n.ithField(j) if field.isNil: - globalError n.info, "invalid field at index " & $i + globalError conf, n.info, "invalid field at index " & $i else: - internalAssert(n.sons[i].kind == nkExprColonExpr) - annotateType(n.sons[i].sons[1], field.typ) + internalAssert(conf, n.sons[i].kind == nkExprColonExpr) + annotateType(n.sons[i].sons[1], field.typ, conf) of nkPar, nkTupleConstr: if x.kind == tyTuple: n.typ = t for i in 0 ..< n.len: - if i >= x.len: globalError n.info, "invalid field at index " & $i - else: annotateType(n.sons[i], x.sons[i]) + if i >= x.len: globalError conf, n.info, "invalid field at index " & $i + else: annotateType(n.sons[i], x.sons[i], conf) elif x.kind == tyProc and x.callConv == ccClosure: n.typ = t else: - globalError(n.info, "() must have a tuple type") + globalError(conf, n.info, "() must have a tuple type") of nkBracket: if x.kind in {tyArray, tySequence, tyOpenArray}: n.typ = t - for m in n: annotateType(m, x.elemType) + for m in n: annotateType(m, x.elemType, conf) else: - globalError(n.info, "[] must have some form of array type") + globalError(conf, n.info, "[] must have some form of array type") of nkCurly: if x.kind in {tySet}: n.typ = t - for m in n: annotateType(m, x.elemType) + for m in n: annotateType(m, x.elemType, conf) else: - globalError(n.info, "{} must have the set type") + globalError(conf, n.info, "{} must have the set type") of nkFloatLit..nkFloat128Lit: if x.kind in {tyFloat..tyFloat128}: n.typ = t else: - globalError(n.info, "float literal must have some float type") + globalError(conf, n.info, "float literal must have some float type") of nkCharLit..nkUInt64Lit: if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}: n.typ = t else: - globalError(n.info, "integer literal must have some int type") + globalError(conf, n.info, "integer literal must have some int type") of nkStrLit..nkTripleStrLit: if x.kind in {tyString, tyCString}: n.typ = t else: - globalError(n.info, "string literal must be of some string type") + globalError(conf, n.info, "string literal must be of some string type") of nkNilLit: if x.kind in NilableTypes: n.typ = t else: - globalError(n.info, "nil literal must be of some pointer type") + globalError(conf, n.info, "nil literal must be of some pointer type") else: discard diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index e12fd84bb2..ea5aab6284 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -23,7 +23,8 @@ import ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs, - renderer, types + renderer, types, modulegraphs, options + from trees import getMagic from strutils import `%` @@ -73,12 +74,15 @@ type # the 'parallel' section currentSpawnId: int inLoop: int + graph: ModuleGraph -proc initAnalysisCtx(): AnalysisCtx = +proc initAnalysisCtx(g: ModuleGraph): AnalysisCtx = result.locals = @[] result.slices = @[] result.args = @[] - result.guards = @[] + result.guards.s = @[] + result.guards.o = initOperators(g) + result.graph = g proc lookupSlot(c: AnalysisCtx; s: PSym): int = for i in 0..= 0 and c.locals[s].stride != nil: - localError(n.info, "invalid usage of counter after increment") + localError(c.graph.config, n.info, "invalid usage of counter after increment") else: for i in 0 ..< n.safeLen: checkLocal(c, n.sons[i]) @@ -126,14 +130,14 @@ template `?`(x): untyped = x.renderTree proc checkLe(c: AnalysisCtx; a, b: PNode) = case proveLe(c.guards, a, b) of impUnknown: - localError(a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)") + localError(c.graph.config, a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)") of impYes: discard of impNo: - localError(a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)") + localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)") proc checkBounds(c: AnalysisCtx; arr, idx: PNode) = checkLe(c, arr.lowBound, idx) - checkLe(c, idx, arr.highBound) + checkLe(c, idx, arr.highBound(c.guards.o)) proc addLowerBoundAsFacts(c: var AnalysisCtx) = for v in c.locals: @@ -142,34 +146,34 @@ proc addLowerBoundAsFacts(c: var AnalysisCtx) = proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) = checkLocal(c, n) - let le = le.canon - let ri = ri.canon + let le = le.canon(c.guards.o) + let ri = ri.canon(c.guards.o) # perform static bounds checking here; and not later! - let oldState = c.guards.len + let oldState = c.guards.s.len addLowerBoundAsFacts(c) c.checkBounds(x, le) c.checkBounds(x, ri) - c.guards.setLen(oldState) + c.guards.s.setLen(oldState) c.slices.add((x, le, ri, c.currentSpawnId, c.inLoop > 0)) -proc overlap(m: TModel; x,y,c,d: PNode) = +proc overlap(m: TModel; conf: ConfigRef; x,y,c,d: PNode) = # X..Y and C..D overlap iff (X <= D and C <= Y) case proveLe(m, c, y) of impUnknown: case proveLe(m, x, d) of impNo: discard of impUnknown, impYes: - localError(x.info, + localError(conf, x.info, "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" % [?c, ?y, ?x, ?y, ?c, ?d]) of impYes: case proveLe(m, x, d) of impUnknown: - localError(x.info, + localError(conf, x.info, "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" % [?x, ?d, ?x, ?y, ?c, ?d]) of impYes: - localError(x.info, "($#)..($#) not disjoint from ($#)..($#)" % + localError(conf, x.info, "($#)..($#) not disjoint from ($#)..($#)" % [?c, ?y, ?x, ?y, ?c, ?d]) of impNo: discard of impNo: discard @@ -187,7 +191,7 @@ proc subStride(c: AnalysisCtx; n: PNode): PNode = if isLocal(n): let s = c.lookupSlot(n.sym) if s >= 0 and c.locals[s].stride != nil: - result = n +@ c.locals[s].stride.intVal + result = buildAdd(n, c.locals[s].stride.intVal, c.guards.o) else: result = n elif n.safeLen > 0: @@ -203,7 +207,7 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) = addLowerBoundAsFacts(c) # Every slice used in a loop needs to be disjoint with itself: for x,a,b,id,inLoop in items(c.slices): - if inLoop: overlap(c.guards, a,b, c.subStride(a), c.subStride(b)) + if inLoop: overlap(c.guards, c.graph.config, a,b, c.subStride(a), c.subStride(b)) # Another tricky example is: # while true: # spawn f(a[i]) @@ -231,21 +235,21 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) = # XXX strictly speaking, 'or' is not correct here and it needs to # be 'and'. However this prevents too many obviously correct programs # like f(a[0..x]); for i in x+1 .. a.high: f(a[i]) - overlap(c.guards, x.a, x.b, y.a, y.b) + overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b) elif (let k = simpleSlice(x.a, x.b); let m = simpleSlice(y.a, y.b); k >= 0 and m >= 0): # ah I cannot resist the temptation and add another sweet heuristic: # if both slices have the form (i+k)..(i+k) and (i+m)..(i+m) we # check they are disjoint and k < stride and m < stride: - overlap(c.guards, x.a, x.b, y.a, y.b) + overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b) let stride = min(c.stride(x.a), c.stride(y.a)) if k < stride and m < stride: discard else: - localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % + localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % [?x.a, ?x.b, ?y.a, ?y.b]) else: - localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % + localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % [?x.a, ?x.b, ?y.a, ?y.b]) proc analyse(c: var AnalysisCtx; n: PNode) @@ -292,31 +296,31 @@ proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) = proc analyseCase(c: var AnalysisCtx; n: PNode) = analyse(c, n.sons[0]) - let oldFacts = c.guards.len + let oldFacts = c.guards.s.len for i in 1.. 1: - addFact(c.guards, canon(branch.sons[0])) + addFact(c.guards, canon(branch.sons[0], c.guards.o)) for i in 0 ..< branch.len: analyse(c, branch.sons[i]) - setLen(c.guards, oldFacts) + setLen(c.guards.s, oldFacts) proc analyse(c: var AnalysisCtx; n: PNode) = case n.kind @@ -349,7 +353,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) = c.addSlice(n, n[0], n[1], n[1]) analyseSons(c, n) of nkReturnStmt, nkRaiseStmt, nkTryStmt: - localError(n.info, "invalid control flow for 'parallel'") + localError(c.graph.config, 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, nkLetSection: @@ -365,7 +369,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) = if it[j].isLocal: let slot = c.getSlot(it[j].sym) if slot.lower.isNil: slot.lower = value - else: internalError(it.info, "slot already has a lower bound") + else: internalError(c.graph.config, it.info, "slot already has a lower bound") if not isSpawned: analyse(c, value) of nkCaseStmt: analyseCase(c, n) of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n) @@ -378,14 +382,14 @@ proc analyse(c: var AnalysisCtx; n: PNode) = else: # loop may never execute: let oldState = c.locals.len - let oldFacts = c.guards.len - addFact(c.guards, canon(n.sons[0])) + let oldFacts = c.guards.s.len + addFact(c.guards, canon(n.sons[0], c.guards.o)) analyse(c, n.sons[1]) setLen(c.locals, oldState) - setLen(c.guards, oldFacts) + setLen(c.guards.s, oldFacts) # we know after the loop the negation holds: if not hasSubnodeWith(n.sons[1], nkBreakStmt): - addFactNeg(c.guards, canon(n.sons[0])) + addFactNeg(c.guards, canon(n.sons[0], c.guards.o)) dec c.inLoop of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef: @@ -393,13 +397,13 @@ proc analyse(c: var AnalysisCtx; n: PNode) = else: analyseSons(c, n) -proc transformSlices(n: PNode): PNode = +proc transformSlices(g: ModuleGraph; n: PNode): PNode = if n.kind in nkCallKinds and n[0].kind == nkSym: let op = n[0].sym if op.name.s == "[]" and op.fromSystem: result = copyNode(n) - let opSlice = newSymNode(createMagic("slice", mSlice)) - opSlice.typ = getSysType(tyInt) + let opSlice = newSymNode(createMagic(g, "slice", mSlice)) + opSlice.typ = getSysType(g, n.info, tyInt) result.add opSlice result.add n[1] let slice = n[2].skipStmtList @@ -409,49 +413,49 @@ proc transformSlices(n: PNode): PNode = if n.safeLen > 0: result = shallowCopy(n) for i in 0 ..< n.len: - result.sons[i] = transformSlices(n.sons[i]) + result.sons[i] = transformSlices(g, n.sons[i]) else: result = n -proc transformSpawn(owner: PSym; n, barrier: PNode): PNode -proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode = +proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode +proc transformSpawnSons(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode = result = shallowCopy(n) for i in 0 ..< n.len: - result.sons[i] = transformSpawn(owner, n.sons[i], barrier) + result.sons[i] = transformSpawn(g, owner, n.sons[i], barrier) -proc transformSpawn(owner: PSym; n, barrier: PNode): PNode = +proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode = case n.kind of nkVarSection, nkLetSection: result = nil for it in n: let b = it.lastSon if getMagic(b) == mSpawn: - if it.len != 3: localError(it.info, "invalid context for 'spawn'") - let m = transformSlices(b) + if it.len != 3: localError(g.config, it.info, "invalid context for 'spawn'") + let m = transformSlices(g, b) if result.isNil: result = newNodeI(nkStmtList, n.info) result.add n let t = b[1][0].typ.sons[0] if spawnResult(t, true) == srByVar: - result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0]) + result.add wrapProcForSpawn(g, owner, m, b.typ, barrier, it[0]) it.sons[it.len-1] = emptyNode else: - it.sons[it.len-1] = wrapProcForSpawn(owner, m, b.typ, barrier, nil) + it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil) if result.isNil: result = n of nkAsgn, nkFastAsgn: let b = n[1] if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0]; spawnResult(t, true) == srByVar): - let m = transformSlices(b) - return wrapProcForSpawn(owner, m, b.typ, barrier, n[0]) - result = transformSpawnSons(owner, n, barrier) + let m = transformSlices(g, b) + return wrapProcForSpawn(g, owner, m, b.typ, barrier, n[0]) + result = transformSpawnSons(g, owner, n, barrier) of nkCallKinds: if getMagic(n) == mSpawn: - result = transformSlices(n) - return wrapProcForSpawn(owner, result, n.typ, barrier, nil) - result = transformSpawnSons(owner, n, barrier) + result = transformSlices(g, n) + return wrapProcForSpawn(g, owner, result, n.typ, barrier, nil) + result = transformSpawnSons(g, owner, n, barrier) elif n.safeLen > 0: - result = transformSpawnSons(owner, n, barrier) + result = transformSpawnSons(g, owner, n, barrier) else: result = n @@ -461,7 +465,7 @@ proc checkArgs(a: var AnalysisCtx; n: PNode) = proc generateAliasChecks(a: AnalysisCtx; result: PNode) = discard "too implement" -proc liftParallel*(owner: PSym; n: PNode): PNode = +proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode = # this needs to be called after the 'for' loop elimination # first pass: @@ -470,17 +474,17 @@ proc liftParallel*(owner: PSym; n: PNode): PNode = # - detect used arguments #echo "PAR ", renderTree(n) - var a = initAnalysisCtx() + var a = initAnalysisCtx(g) let body = n.lastSon analyse(a, body) if a.spawns == 0: - localError(n.info, "'parallel' section without 'spawn'") + localError(g.config, n.info, "'parallel' section without 'spawn'") checkSlicesAreDisjoint(a) checkArgs(a, body) var varSection = newNodeI(nkVarSection, n.info) var temp = newSym(skTemp, getIdent"barrier", owner, n.info) - temp.typ = magicsys.getCompilerProc("Barrier").typ + temp.typ = magicsys.getCompilerProc(g, "Barrier").typ incl(temp.flags, sfFromGeneric) let tempNode = newSymNode(temp) varSection.addVar tempNode @@ -489,6 +493,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 transformSpawn(owner, body, barrier) - result.add callCodegenProc("closeBarrier", barrier) + result.add callCodegenProc(g, "openBarrier", barrier) + result.add transformSpawn(g, owner, body, barrier) + result.add callCodegenProc(g, "closeBarrier", barrier) diff --git a/compiler/vm.nim b/compiler/vm.nim index 6c36a14580..84057e6566 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -19,7 +19,7 @@ import ast except getstr import strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, parser, vmdeps, idents, trees, renderer, options, transf, parseutils, - vmmarshal, gorgeimpl + vmmarshal, gorgeimpl, configuration from semfold import leValueConv, ordinalValToString from evaltempl import evalTemplate @@ -81,16 +81,16 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = msgWriteln(s) proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, - msg: TMsgKind, arg = "", n: PNode = nil) = + msg: string, n: PNode = nil) = msgWriteln("stack trace: (most recent call last)") stackTraceAux(c, tos, pc) # XXX test if we want 'globalError' for every mode let lineInfo = if n == nil: c.debug[pc] else: n.info - if c.mode == emRepl: globalError(lineInfo, msg, arg) - else: localError(lineInfo, msg, arg) + if c.mode == emRepl: globalError(c.config, lineInfo, msg) + else: localError(c.config, lineInfo, msg) proc bailOut(c: PCtx; tos: PStackFrame) = - stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX, + stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " & c.currentExceptionA.sons[3].skipColon.strVal) when not defined(nimComputedGoto): @@ -308,7 +308,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int = return pc return -1 -proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool = +proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool = if desttyp.kind == tyString: if dest.kind != rkNode: myreset(dest) @@ -323,7 +323,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool = dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal else: for i in 0.. max: - stackTrace(c, tos, pc, errGenerated, - msgKindToString(errUnhandledExceptionX) % "value out of range") + stackTrace(c, tos, pc, "unhandled exception: value out of range") of opcNarrowU: decodeB(rkInt) regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1) @@ -1217,7 +1227,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if u.kind notin {nkEmpty..nkNilLit}: u.add(regs[rc].node) else: - stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind) + stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind) regs[ra].node = u of opcNAddMultiple: decodeBC(rkNode) @@ -1227,7 +1237,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # XXX can be optimized: for i in 0.. ord(high(TNodeKind)): - internalError(c.debug[pc], + internalError(c.config, c.debug[pc], "request to create a NimNode of invalid kind") let cc = regs[rc].node @@ -1548,7 +1559,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let name = if regs[rc].node.strVal.len == 0: ":tmp" else: regs[rc].node.strVal if k < 0 or k > ord(high(TSymKind)): - internalError(c.debug[pc], "request to create symbol of invalid kind") + internalError(c.config, c.debug[pc], "request to create symbol of invalid kind") var sym = newSym(k.TSymKind, name.getIdent, c.module.owner, c.debug[pc]) incl(sym.flags, sfGenSym) regs[ra].node = newSymNode(sym) @@ -1557,7 +1568,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # type trait operation decodeB(rkNode) var typ = regs[rb].node.typ - internalAssert typ != nil + internalAssert c.config, typ != nil while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0] createStr regs[ra] regs[ra].node.strVal = typ.typeToString(preferExported) @@ -1566,14 +1577,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let rb = instr.regB inc pc let typ = c.types[c.code[pc].regBx - wordExcess] - putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ)) + putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.config)) of opcMarshalStore: decodeB(rkNode) inc pc let typ = c.types[c.code[pc].regBx - wordExcess] createStrKeepNode(regs[ra]) if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000) - storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode) + storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config) of opcToNarrowInt: decodeBC(rkInt) let mask = (1'i64 shl rc) - 1 # 0xFF @@ -1595,7 +1606,7 @@ proc execute(c: PCtx, start: int): PNode = proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = if sym.kind in routineKinds: if sym.typ.len-1 != args.len: - localError(sym.info, + localError(c.config, sym.info, "NimScript: expected $# arguments, but got $#" % [ $(sym.typ.len-1), $args.len]) else: @@ -1607,18 +1618,18 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = # setup parameters: if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro: - putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info)) + putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info, c.config)) # XXX We could perform some type checking here. for i in 1.. evalMacroLimit: - globalError(n.info, errMacroInstantiationTooNested) + globalError(g.config, n.info, "macro instantiation too nested") # immediate macros can bypass any type and arity checking so we check the # arity here too: if sym.typ.len > n.safeLen and sym.typ.len > 1: - globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [ + globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [ n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) - setupGlobalCtx(module, cache, config) + setupGlobalCtx(module, cache, g) var c = globalCtx c.comesFromHeuristic.line = 0'u16 @@ -1781,16 +1791,16 @@ proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef; else: dec(evalMacroCounter) c.callsite = nil - localError(n.info, "expected " & $gp.len & + localError(c.config, n.info, "expected " & $gp.len & " generic parameter(s)") elif gp[i].sym.typ.kind in {tyStatic, tyTypeDesc}: dec(evalMacroCounter) c.callsite = nil - globalError(n.info, "static[T] or typedesc nor supported for .immediate macros") + globalError(c.config, n.info, "static[T] or typedesc nor supported for .immediate macros") # temporary storage: #for i in L ..< maxSlots: tos.slots[i] = newNode(nkEmpty) result = rawExecute(c, start, tos).regToNode if result.info.line < 0: result.info = n.info - if cyclicTree(result): globalError(n.info, errCyclicTree) + if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree") dec(evalMacroCounter) c.callsite = nil diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 56ee45b6cb..e10a620066 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -208,6 +208,7 @@ type cache*: IdentCache config*: ConfigRef graph*: ModuleGraph + oldErrorCount*: int TPosition* = distinct int diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 7f8bf06c10..617295b0da 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -15,8 +15,6 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir -from options import gProjectPath - template mathop(op) {.dirty.} = registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`) @@ -77,15 +75,15 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode = result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord), newStrNode(nkStrLit, f)) -proc gorgeExWrapper(a: VmArgs) {.nimcall.} = - let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), - a.currentLineInfo) - setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e)) - -proc getProjectPathWrapper(a: VmArgs) {.nimcall.} = - setResult a, gProjectPath - proc registerAdditionalOps*(c: PCtx) = + proc gorgeExWrapper(a: VmArgs) = + let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), + a.currentLineInfo, c.config) + setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e)) + + proc getProjectPathWrapper(a: VmArgs) = + setResult a, c.config.projectPath + wrap1f_math(sqrt) wrap1f_math(ln) wrap1f_math(log10) From ce859d8c166595184832b4bbfb663cba2fc68901 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 16:35:59 +0200 Subject: [PATCH 188/214] more modules compile again --- compiler/configuration.nim | 19 +-- compiler/evaltempl.nim | 2 +- compiler/hlo.nim | 12 +- compiler/nimfix/pretty.nim | 4 +- compiler/sem.nim | 29 ++-- compiler/semcall.nim | 59 +++---- compiler/semexprs.nim | 214 ++++++++++++------------- compiler/semfields.nim | 10 +- compiler/seminst.nim | 27 ++-- compiler/semmagic.nim | 28 ++-- compiler/semobjconstr.nim | 22 +-- compiler/semstmts.nim | 248 ++++++++++++++--------------- compiler/semtempl.nim | 77 ++++----- compiler/semtypes.nim | 309 ++++++++++++++++++++----------------- compiler/vm.nim | 2 +- 15 files changed, 544 insertions(+), 518 deletions(-) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index b2548eb742..4b3cecfcab 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -229,7 +229,6 @@ errXExpectsArrayType: "'$1' expects an array type", errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", errExprXAmbiguous: "expression '$1' ambiguous in this context", errConstantDivisionByZero: , -errOrdinalTypeExpected: "ordinal type expected", errOrdinalOrFloatTypeExpected: "ordinal or float type expected", errOverOrUnderflow: , errCannotEvalXBecauseIncompletelyDefined: , @@ -274,9 +273,6 @@ errConstNeedsConstExpr: "a constant can only be initialized with a constant expr errConstNeedsValue: "a constant needs a value", errResultCannotBeOpenArray: "the result type cannot be on open array", errSizeTooBig: "computing the type's size produced an overflow", -errSetTooBig: "set is too large", -errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal", -errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects", errInheritanceOnlyWithEnums: "inheritance only works with an enum", errIllegalRecursionInTypeX:, errCannotInstantiateX: "cannot instantiate: '$1'", @@ -293,7 +289,6 @@ errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", errXCannotBePassedToProcVar: , errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", -errImplOfXNotAllowed: "implementation of '$1' is not allowed", errImplOfXexpected: , errNoSymbolToBorrowFromFound: "no symbol to borrow from found", errDiscardValueX: "value of type '$1' has to be discarded", @@ -312,7 +307,7 @@ errUnknownSubstitionVar: "unknown substitution variable: '$1'", errComplexStmtRequiresInd: "complex statement requires indentation", errXisNotCallable: "'$1' is not callable", errNoPragmasAllowedForX: "no pragmas allowed for $1", -errNoGenericParamsAllowedForX: "no generic parameters allowed for $1", +, errInvalidParamKindX: "invalid param kind: '$1'", errDefaultArgumentInvalid: "default argument invalid", errNamedParamHasToBeIdent: "named parameter has to be an identifier", @@ -328,17 +323,8 @@ errInvalidExpressionX: "invalid expression: '$1'", errEnumHasNoValueX: "enum has no value '$1'", errNamedExprExpected: "named expression expected", errNamedExprNotAllowed: "named expression not allowed here", -errXExpectsOneTypeParam: "'$1' expects one type parameter", -errArrayExpectsTwoTypeParams: "array expects two type parameters", -errInvalidVisibilityX: "invalid visibility: '$1'", -errInitHereNotAllowed: "initialization not allowed here", -errXCannotBeAssignedTo: "'$1' cannot be assigned to", -errIteratorNotAllowed: "iterators can only be defined at the module's top level", -errXNeedsReturnType: "$1 needs a return type", -errNoReturnTypeDeclared: "no return type declared", errNoCommand: "no command given", errInvalidCommandX: "invalid command: '$1'", -errXOnlyAtModuleScope: "'$1' is only allowed at top level", errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N", errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N", @@ -347,7 +333,7 @@ errInvalidIndexValueForTuple: "invalid index value for tuple subscript", errCommandExpectsFilename: "command expects a filename argument", errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", errXExpected: "'$1' expected", -errTIsNotAConcreteType: "'$1' is not a concrete type.", +, errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'", errInvalidSectionStart: "invalid section start", errGridTableNotImplemented: "grid table is not implemented", @@ -396,5 +382,4 @@ errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when "it is used as an operand to another routine and the types " & "of the generic paramers can be inferred from the expected signature.", errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.", -errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types", ]# diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 2133701e66..311bb6539e 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -114,7 +114,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode # to prevent endless recursion in template instantiation const evalTemplateLimit* = 1000 -var evalTemplateCounter* = 0 +var evalTemplateCounter* = 0 # XXX remove this global proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = when true: diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 3e19be6e90..76404e49b6 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -17,7 +17,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode = # aweful to semcheck before macro invocation, so we don't and treat # templates and macros as immediate in this context. var rule: string - if optHints in gOptions and hintPattern in gNotes: + if optHints in gOptions and hintPattern in c.config.notes: rule = renderTree(n, {renderNoComments}) let s = n.sons[0].sym case s.kind @@ -27,8 +27,8 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode = result = semTemplateExpr(c, n, s, {efFromHlo}) else: result = semDirectOp(c, n, {}) - if optHints in gOptions and hintPattern in gNotes: - message(orig.info, hintPattern, rule & " --> '" & + if optHints in gOptions and hintPattern in c.config.notes: + message(c.config, orig.info, hintPattern, rule & " --> '" & renderTree(result, {renderNoComments}) & "'") proc applyPatterns(c: PContext, n: PNode): PNode = @@ -45,7 +45,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode = # better be safe than sorry, so check evalTemplateCounter too: inc(evalTemplateCounter) if evalTemplateCounter > evalTemplateLimit: - globalError(n.info, errTemplateInstantiationTooNested) + globalError(c.config, n.info, "template instantiation too nested") # deactivate this pattern: c.patterns[i] = nil if x.kind == nkStmtList: @@ -86,9 +86,9 @@ proc hlo(c: PContext, n: PNode): PNode = else: result = fitNode(c, n.typ, result, n.info) # optimization has been applied so check again: - result = commonOptimizations(c.module, result) + result = commonOptimizations(c.graph, c.module, result) result = hlo(c, result) - result = commonOptimizations(c.module, result) + result = commonOptimizations(c.graph, c.module, result) proc hloBody(c: PContext, n: PNode): PNode = # fast exit: diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim index c68c3ccf16..96429ad535 100644 --- a/compiler/nimfix/pretty.nim +++ b/compiler/nimfix/pretty.nim @@ -132,9 +132,9 @@ template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) = if gStyleCheck != StyleCheck.None: styleCheckDefImpl(conf, info, s, k) template styleCheckDef*(info: TLineInfo; s: PSym) = - styleCheckDef(conf, info, s, s.kind) + styleCheckDef(info, s, s.kind) template styleCheckDef*(s: PSym) = - styleCheckDef(conf, s.info, s, s.kind) + styleCheckDef(s.info, s, s.kind) proc styleCheckUseImpl(info: TLineInfo; s: PSym) = if info.fileIndex.int < 0: return diff --git a/compiler/sem.nim b/compiler/sem.nim index ae32ecb8a0..de0b2d3064 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -16,7 +16,7 @@ import procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity, - semparallel, lowerings, pluginsupport, plugins.active, rod + semparallel, lowerings, pluginsupport, plugins.active, rod, configuration from modulegraphs import ModuleGraph @@ -382,7 +382,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, ## contains. inc(evalTemplateCounter) if evalTemplateCounter > evalTemplateLimit: - globalError(s.info, errTemplateInstantiationTooNested) + globalError(c.config, s.info, "template instantiation too nested") c.friendModules.add(s.owner.getModule) result = macroResult @@ -424,43 +424,46 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, dec(evalTemplateCounter) discard c.friendModules.pop() +const + errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters" + proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, flags: TExprFlags = {}): PNode = pushInfoContext(nOrig.info) - markUsed(n.info, sym, c.graph.usageSym) + markUsed(c.config, n.info, sym, c.graph.usageSym) styleCheckUse(n.info, sym) if sym == c.p.owner: - globalError(n.info, errRecursiveDependencyX, sym.name.s) + globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s) let genericParams = if sfImmediate in sym.flags: 0 else: sym.ast[genericParamsPos].len let suppliedParams = max(n.safeLen - 1, 0) if suppliedParams < genericParams: - globalError(n.info, errMissingGenericParamsForTemplate, n.renderTree) + globalError(c.config, n.info, errMissingGenericParamsForTemplate % n.renderTree) #if c.evalContext == nil: # c.evalContext = c.createEvalContext(emStatic) - result = evalMacroCall(c.module, c.cache, c.graph.config, n, nOrig, sym) + result = evalMacroCall(c.module, c.cache, c.graph, n, nOrig, sym) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, sym, flags) result = wrapInComesFrom(nOrig.info, sym, result) popInfoContext() proc forceBool(c: PContext, n: PNode): PNode = - result = fitNode(c, getSysType(tyBool), n, n.info) + result = fitNode(c, getSysType(c.graph, n.info, tyBool), n, n.info) if result == nil: result = n proc semConstBoolExpr(c: PContext, n: PNode): PNode = let nn = semExprWithType(c, n) - result = fitNode(c, getSysType(tyBool), nn, nn.info) + result = fitNode(c, getSysType(c.graph, n.info, tyBool), nn, nn.info) if result == nil: - localError(n.info, errConstExprExpected) + localError(c.config, n.info, errConstExprExpected) return nn - result = getConstExpr(c.module, result) + result = getConstExpr(c.module, result, c.graph) if result == nil: - localError(n.info, errConstExprExpected) + localError(c.config, n.info, errConstExprExpected) result = nn proc semGenericStmt(c: PContext, n: PNode): PNode @@ -480,7 +483,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) = proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = var c = newContext(graph, module, cache) - if c.p != nil: internalError(module.info, "sem.myOpen") + if c.p != nil: internalError(graph.config, module.info, "sem.myOpen") c.semConstExpr = semConstExpr c.semExpr = semExpr c.semTryExpr = tryExpr @@ -532,7 +535,7 @@ proc isImportSystemStmt(n: PNode): bool = proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = if n.kind == nkDefer: - localError(n.info, "defer statement not supported at top level") + localError(c.config, n.info, "defer statement not supported at top level") if c.topStmts == 0 and not isImportSystemStmt(n): if sfSystemModule notin c.module.flags and n.kind notin {nkEmpty, nkCommentStmt}: diff --git a/compiler/semcall.nim b/compiler/semcall.nim index aa53fda3b4..b4d4cad7e6 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -202,24 +202,31 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): result = (prefer, candidates) +const + errTypeMismatch = "type mismatch: got <" + errButExpected = "but expected one of: " + errUndeclaredField = "undeclared field: '$1'" + errUndeclaredRoutine = "attempting to call undeclared routine: '$1'" + errAmbiguousCallXYZ = "ambiguous call; both $1 and $2 match for: $3" + 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). if errorOutputs == {}: # fail fast: - globalError(n.info, errTypeMismatch, "") + globalError(c.config, n.info, "type mismatch") if errors.len == 0: - localError(n.info, errExprXCannotBeCalled, n[0].renderTree) + localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree) return let (prefer, candidates) = presentFailedCandidates(c, n, errors) - var result = msgKindToString(errTypeMismatch) + var result = errTypeMismatch add(result, describeArgs(c, n, 1, prefer)) add(result, '>') if candidates != "": - add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) - localError(n.info, errGenerated, result & "\nexpression: " & $n) + add(result, "\n" & errButExpected & "\n" & candidates) + localError(c.config, n.info, result & "\nexpression: " & $n) proc bracketNotFoundError(c: PContext; n: PNode) = var errors: CandidateErrors = @[] @@ -234,7 +241,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) = enabled: false)) symx = nextOverloadIter(o, c, headSymbol) if errors.len == 0: - localError(n.info, "could not resolve: " & $n) + localError(c.config, n.info, "could not resolve: " & $n) else: notFoundError(c, n, errors) @@ -277,7 +284,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, else: return if nfDotField in n.flags: - internalAssert f.kind == nkIdent and n.sonsLen >= 2 + internalAssert c.config, f.kind == nkIdent and n.len >= 2 # leave the op head symbol empty, # we are going to try multiple variants @@ -306,13 +313,13 @@ proc resolveOverloads(c: PContext, n, orig: PNode, if overloadsState == csEmpty and result.state == csEmpty: if nfDotField in n.flags and nfExplicitCall notin n.flags: - localError(n.info, errUndeclaredField, considerQuotedIdent(f, n).s) + localError(c.config, n.info, errUndeclaredField % considerQuotedIdent(c.config, f, n).s) else: - localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f, n).s) + localError(c.config, n.info, errUndeclaredRoutine % considerQuotedIdent(c.config, f, n).s) return elif result.state != csMatch: if nfExprCall in n.flags: - localError(n.info, errExprXCannotBeCalled, + localError(c.config, n.info, "expression '$1' cannot be called" % renderTree(n, {renderNoComments})) else: if {nfDotField, nfDotSetter} * n.flags != {}: @@ -322,13 +329,13 @@ proc resolveOverloads(c: PContext, n, orig: PNode, return if alt.state == csMatch and cmpCandidates(result, alt) == 0 and not sameMethodDispatcher(result.calleeSym, alt.calleeSym): - internalAssert result.state == csMatch + internalAssert c.config, result.state == csMatch #writeMatches(result) #writeMatches(alt) if errorOutputs == {}: # quick error message for performance of 'compiles' built-in: - globalError(n.info, errGenerated, "ambiguous call") - elif gErrorCounter == 0: + globalError(c.config, n.info, errGenerated, "ambiguous call") + elif c.config.errorCounter == 0: # don't cascade errors var args = "(" for i in countup(1, sonsLen(n) - 1): @@ -336,7 +343,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, add(args, typeToString(n.sons[i].typ)) add(args, ")") - localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [ + localError(c.config, n.info, errAmbiguousCallXYZ % [ getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym), args]) @@ -377,7 +384,7 @@ proc inferWithMetatype(c: PContext, formal: PType, result.typ = generateTypeInstance(c, m.bindings, arg.info, formal.skipTypes({tyCompositeTypeClass})) else: - typeMismatch(arg.info, formal, arg.typ) + typeMismatch(c.config, arg.info, formal, arg.typ) # error correction: result = copyTree(arg) result.typ = formal @@ -385,7 +392,7 @@ proc inferWithMetatype(c: PContext, formal: PType, proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = assert x.state == csMatch var finalCallee = x.calleeSym - markUsed(n.sons[0].info, finalCallee, c.graph.usageSym) + markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym) styleCheckUse(n.sons[0].info, finalCallee) assert finalCallee.ast != nil if x.hasFauxMatch: @@ -411,7 +418,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = of skType: x.call.add newSymNode(s, n.info) else: - internalAssert false + internalAssert c.config, false result = x.call instGenericConvertersSons(c, result, x) @@ -435,7 +442,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, # this may be triggered, when the explain pragma is used if errors.len > 0: let (_, candidates) = presentFailedCandidates(c, n, errors) - message(n.info, hintUserRaw, + message(c.config, n.info, hintUserRaw, "Non-matching candidates for " & renderTree(n) & "\n" & candidates) result = semResolvedCall(c, n, r) @@ -468,8 +475,8 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, else: notFoundError(c, n, errors) -proc explicitGenericInstError(n: PNode): PNode = - localError(n.info, errCannotInstantiateX, renderTree(n)) +proc explicitGenericInstError(c: PContext; n: PNode): PNode = + localError(c.config, n.info, errCannotInstantiateX % renderTree(n)) result = n proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = @@ -484,7 +491,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = if tm in {isNone, isConvertible}: return nil var newInst = generateInstance(c, s, m.bindings, n.info) newInst.typ.flags.excl tfUnresolved - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(newInst, n.info) @@ -500,11 +507,11 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = # number of generic type parameters: if safeLen(s.ast.sons[genericParamsPos]) != n.len-1: let expected = safeLen(s.ast.sons[genericParamsPos]) - localError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) & + localError(c.config, n.info, errGenerated, "cannot instantiate: " & renderTree(n) & "; got " & $(n.len-1) & " type(s) but expected " & $expected) return n result = explicitGenericSym(c, n, s) - if result == nil: result = explicitGenericInstError(n) + if result == nil: result = explicitGenericInstError(c, n) 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. @@ -522,10 +529,10 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = # get rid of nkClosedSymChoice if not ambiguous: if result.len == 1 and a.kind == nkClosedSymChoice: result = result[0] - elif result.len == 0: result = explicitGenericInstError(n) - # candidateCount != 1: return explicitGenericInstError(n) + elif result.len == 0: result = explicitGenericInstError(c, n) + # candidateCount != 1: return explicitGenericInstError(c, n) else: - result = explicitGenericInstError(n) + result = explicitGenericInstError(c, n) proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = # Searchs for the fn in the symbol table. If the parameter lists are suitable diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 4a3672aa0d..001e0ccf22 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -31,12 +31,12 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.typ != nil: # XXX tyGenericInst here? if result.typ.kind == tyProc and tfUnresolved in result.typ.flags: - localError(n.info, errProcHasNoConcreteType, n.renderTree) + localError(c.config, n.info, errProcHasNoConcreteType, n.renderTree) if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyVoid, c) else: - localError(n.info, errExprXHasNoType, + localError(c.config, n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) result.typ = errorType(c) @@ -47,7 +47,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = #raiseRecoverableError("") result = errorNode(c, n) if result.typ == nil or result.typ == enforceVoidContext: - localError(n.info, errExprXHasNoType, + localError(c.config, n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) result.typ = errorType(c) else: @@ -59,7 +59,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # do not produce another redundant error message: result = errorNode(c, n) if result.typ == nil: - localError(n.info, errExprXHasNoType, + localError(c.config, n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) result.typ = errorType(c) @@ -69,7 +69,7 @@ proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = proc inlineConst(n: PNode, s: PSym): PNode {.inline.} = result = copyTree(s.ast) if result.isNil: - localError(n.info, "constant of type '" & typeToString(s.typ) & "' has no value") + localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value") result = newSymNode(s) else: result.typ = s.typ @@ -172,7 +172,7 @@ proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) = proc semConv(c: PContext, n: PNode): PNode = if sonsLen(n) != 2: - localError(n.info, errConvNeedsOneArg) + localError(c.config, n.info, errConvNeedsOneArg) return n result = newNodeI(nkConv, n.info) @@ -192,7 +192,7 @@ proc semConv(c: PContext, n: PNode): PNode = # special case to make MyObject(x = 3) produce a nicer error message: if n[1].kind == nkExprEqExpr and targetType.skipTypes(abstractPtrs).kind == tyObject: - localError(n.info, "object contruction uses ':', not '='") + localError(c.config, n.info, "object contruction uses ':', not '='") var op = semExprWithType(c, n.sons[1]) if targetType.isMetaType: let final = inferWithMetatype(c, targetType, op, true) @@ -219,7 +219,7 @@ proc semConv(c: PContext, n: PNode): PNode = of convNotLegal: result = fitNode(c, result.typ, result.sons[1], result.info) if result == nil: - localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)% + localError(c.config, n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)% [op.typ.typeToString, result.typ.typeToString]) else: for i in countup(0, sonsLen(op) - 1): @@ -234,16 +234,16 @@ proc semConv(c: PContext, n: PNode): PNode = proc semCast(c: PContext, n: PNode): PNode = ## Semantically analyze a casting ("cast[type](param)") - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) let targetType = semTypeNode(c, n.sons[0], nil) let castedExpr = semExprWithType(c, n.sons[1]) if tfHasMeta in targetType.flags: - localError(n.sons[0].info, errCastToANonConcreteType, $targetType) + localError(c.config, n.sons[0].info, errCastToANonConcreteType, $targetType) if not isCastable(targetType, castedExpr.typ): let tar = $targetType let alt = typeToString(targetType, preferDesc) let msg = if tar != alt: tar & "=" & alt else: tar - localError(n.info, errExprCannotBeCastToX, msg) + localError(c.config, n.info, errExprCannotBeCastToX, msg) result = newNodeI(nkCast, n.info) result.typ = targetType addSon(result, copyTree(n.sons[0])) @@ -253,7 +253,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = const opToStr: array[mLow..mHigh, string] = ["low", "high"] if sonsLen(n) != 2: - localError(n.info, errXExpectsTypeOrValue, opToStr[m]) + localError(c.config, n.info, errXExpectsTypeOrValue, opToStr[m]) else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc}) @@ -271,12 +271,12 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = # that could easily turn into an infinite recursion in semtypinst n.typ = makeTypeFromExpr(c, n.copyTree) else: - localError(n.info, errInvalidArgForX, opToStr[m]) + localError(c.config, n.info, errInvalidArgForX, opToStr[m]) result = n proc semSizeof(c: PContext, n: PNode): PNode = if sonsLen(n) != 2: - localError(n.info, errXExpectsTypeOrValue, "sizeof") + localError(c.config, n.info, errXExpectsTypeOrValue, "sizeof") else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) #restoreOldStyleType(n.sons[1]) @@ -315,7 +315,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode = if sonsLen(n) != 3: - localError(n.info, errXExpectsTwoArguments, "is") + localError(c.config, n.info, errXExpectsTwoArguments, "is") result = n n.typ = getSysType(tyBool) @@ -396,7 +396,7 @@ proc changeType(n: PNode, newType: PType, check: bool) = if check and n.kind != nkUInt64Lit: let value = n.intVal if value < firstOrd(newType) or value > lastOrd(newType): - localError(n.info, errGenerated, "cannot convert " & $value & + localError(c.config, n.info, errGenerated, "cannot convert " & $value & " to " & typeToString(newType)) else: discard n.typ = newType @@ -438,7 +438,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var idx = semConstExpr(c, x.sons[0]) idx = fitNode(c, indexType, idx, x.info) if lastIndex+1 != getOrdValue(idx): - localError(x.info, errInvalidOrderInArrayConstructor) + localError(c.config, x.info, errInvalidOrderInArrayConstructor) x = x.sons[1] let xx = semExprWithType(c, x, flags*{efAllowDestructor}) @@ -471,13 +471,13 @@ proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags): - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) result = n.sons[0] else: result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ)) addSon(result, n) if isAssignable(c, n) notin {arLValue, arLocalLValue}: - localError(n.info, errVarForOutParamNeededX, renderNotLValue(n)) + localError(c.config, n.info, errVarForOutParamNeededX, renderNotLValue(n)) proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = result = n @@ -489,7 +489,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = incl(n.sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) of nkDotExpr: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) if n.sons[1].kind != nkSym: internalError(n.info, "analyseIfAddressTaken") return @@ -497,7 +497,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = incl(n.sons[1].sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) of nkBracketExpr: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}: if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) @@ -505,7 +505,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = result = newHiddenAddrTaken(c, n) proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) const FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, @@ -524,14 +524,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = let it = n[i] if isAssignable(c, it) notin {arLValue, arLocalLValue}: if it.kind != nkHiddenAddr: - localError(it.info, errVarForOutParamNeededX, $it) + localError(c.config, it.info, errVarForOutParamNeededX % $it) # bug #5113: disallow newSeq(result) where result is a 'var T': if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}: var arg = n[1] #.skipAddr if arg.kind == nkHiddenDeref: arg = arg[0] if arg.kind == nkSym and arg.sym.kind == skResult and arg.typ.skipTypes(abstractInst).kind in {tyVar, tyLent}: - localError(n.info, errXStackEscape, renderTree(n[1], {renderNoComments})) + localError(c.config, n.info, errXStackEscape % renderTree(n[1], {renderNoComments})) return for i in countup(1, sonsLen(n) - 1): @@ -560,14 +560,14 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = call.add(n.sons[0]) var allConst = true for i in 1 ..< n.len: - var a = getConstExpr(c.module, n.sons[i]) + var a = getConstExpr(c.module, n.sons[i], c.graph) if a == nil: allConst = false a = n.sons[i] if a.kind == nkHiddenStdConv: a = a.sons[1] call.add(a) if allConst: - result = semfold.getConstExpr(c.module, call) + result = semfold.getConstExpr(c.module, call, c.graph) if result.isNil: result = n else: return result @@ -607,7 +607,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = if sfCompileTime in callee.flags: result = evalStaticExpr(c.module, c.cache, c.graph.config, call, c.p.owner) if result.isNil: - localError(n.info, errCannotInterpretNodeX, renderTree(call)) + localError(c.config, n.info, errCannotInterpretNodeX, renderTree(call)) else: result = fixupTypeAfterEval(c, result, n) else: result = evalConstExpr(c.module, c.cache, c.graph.config, call) @@ -621,7 +621,7 @@ proc semStaticExpr(c: PContext, n: PNode): PNode = if a.findUnresolvedStatic != nil: return a result = evalStaticExpr(c.module, c.cache, c.graph.config, a, c.p.owner) if result.isNil: - localError(n.info, errCannotInterpretNodeX, renderTree(n)) + localError(c.config, n.info, errCannotInterpretNodeX, renderTree(n)) result = emptyNode else: result = fixupTypeAfterEval(c, result, a) @@ -648,7 +648,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, of skMacro, skTemplate: discard else: if callee.kind == skIterator and callee.id == c.p.owner.id: - localError(n.info, errRecursiveDependencyX, callee.name.s) + localError(c.config, n.info, errRecursiveDependencyX, callee.name.s) # error correction, prevents endless for loop elimination in transf. # See bug #2051: result.sons[0] = newSymNode(errorSym(c, n)) @@ -696,10 +696,10 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode = proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = result = nil - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) var prc = n.sons[0] if n.sons[0].kind == nkDotExpr: - checkSonsLen(n.sons[0], 2) + checkSonsLen(n.sons[0], 2, c.config) let n0 = semFieldAccess(c, n.sons[0]) if n0.kind == nkDotCall: # it is a static call! @@ -732,7 +732,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = if m.state != csMatch: if errorOutputs == {}: # speed up error generation: - globalError(n.info, errTypeMismatch, "") + globalError(c.config, n.info, "type mismatch") return emptyNode else: var hasErrorType = false @@ -747,7 +747,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = if not hasErrorType: add(msg, ">\n" & msgKindToString(errButExpected) & "\n" & typeToString(n.sons[0].typ)) - localError(n.info, errGenerated, msg) + localError(c.config, n.info, msg) return errorNode(c, n) result = nil else: @@ -794,7 +794,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = if e != nil: add(result, newSymNode(e)) else: - localError(n.info, errSystemNeeds, "echo") + localError(c.config, n.info, "system needs: echo") add(result, errorNode(c, n)) add(result, n) result = semExpr(c, result) @@ -838,8 +838,8 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, result = lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check) if result != nil: return of nkRecCase: - checkMinSonsLen(r, 2) - if (r.sons[0].kind != nkSym): illFormedAst(r) + checkMinSonsLen(r, 2, c.config) + if (r.sons[0].kind != nkSym): illFormedAst(r, c.config) result = lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check) if result != nil: return let setType = createSetType(c, r.sons[0].typ) @@ -879,10 +879,10 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, addSon(notExpr, inExpr) addSon(check, notExpr) return - else: illFormedAst(it) + else: illFormedAst(it, c.config) of nkSym: if r.sym.name.id == field.id: result = r.sym - else: illFormedAst(n) + else: illFormedAst(n, c.config) const tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass} @@ -995,7 +995,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = result = newSymNode(s, n.info) of skVar, skLet, skResult, skForVar: if s.magic == mNimvm: - localError(n.info, "illegal context for 'nimvm' magic") + localError(c.config, n.info, "illegal context for 'nimvm' magic") markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) @@ -1060,7 +1060,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if it's not a built-in field access - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) # tests/bind/tbindoverload.nim wants an early exit here, but seems to # work without now. template/tsymchoicefield doesn't like an early exit # here at all! @@ -1222,7 +1222,7 @@ proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode = for i in 0 .. n.len-1: result.add(n[i]) proc semDeref(c: PContext, n: PNode): PNode = - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) n.sons[0] = semExprWithType(c, n.sons[0]) result = n var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink}) @@ -1240,7 +1240,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result = newNodeIT(nkDerefExpr, x.info, x.typ) result.add(x[0]) return - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) # make sure we don't evaluate generic macros/templates n.sons[0] = semExprWithType(c, n.sons[0], {efNoEvaluateGeneric}) @@ -1277,7 +1277,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = {tyInt..tyInt64}: var idx = getOrdValue(n.sons[1]) if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)] - else: localError(n.info, errInvalidIndexValueForTuple) + else: localError(c.config, n.info, errInvalidIndexValueForTuple) result = n else: result = nil @@ -1340,10 +1340,10 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = let root = exprRoot(n) if root != nil and root.owner == c.p.owner: if root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags: - localError(n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [ + localError(c.config, n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [ root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl]) elif root.kind == skParam and root.position != 0: - localError(n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [ + localError(c.config, n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [ root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl]) case n.kind of nkHiddenAddr, nkAddr: return n @@ -1354,9 +1354,9 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = let valid = isAssignable(c, n) if valid != arLValue: if valid == arLocalLValue: - localError(n.info, errXStackEscape, renderTree(n, {renderNoComments})) + localError(c.config, n.info, errXStackEscape, renderTree(n, {renderNoComments})) elif not isLent: - localError(n.info, errExprHasNoAddress) + localError(c.config, n.info, errExprHasNoAddress) result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ)) result.add(n) @@ -1373,7 +1373,7 @@ template resultTypeIsInferrable(typ: PType): untyped = typ.isMetaType and typ.kind != tyTypeDesc proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) var a = n.sons[0] case a.kind of nkDotExpr: @@ -1426,7 +1426,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = isAssignable(c, a) == arNone) or skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}: # Direct assignment to a discriminant is allowed! - localError(a.info, errXCannotBeAssignedTo, + localError(c.config, a.info, errXCannotBeAssignedTo, renderTree(a, {renderNoComments})) else: let @@ -1463,7 +1463,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = proc semReturn(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or ( c.p.owner.kind == skIterator and c.p.owner.typ.callConv == ccClosure): if n.sons[0].kind != nkEmpty: @@ -1477,9 +1477,9 @@ proc semReturn(c: PContext, n: PNode): PNode = if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym: n.sons[0] = ast.emptyNode else: - localError(n.info, errNoReturnTypeDeclared) + localError(c.config, n.info, errNoReturnTypeDeclared) else: - localError(n.info, errXNotAllowedHere, "\'return\'") + localError(c.config, n.info, errXNotAllowedHere, "\'return\'") proc semProcBody(c: PContext, n: PNode): PNode = openScope(c) @@ -1510,7 +1510,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = c.p.resultSym.typ = errorType(c) c.p.owner.typ.sons[0] = nil else: - localError(c.p.resultSym.info, errCannotInferReturnType) + localError(c.config, c.p.resultSym.info, errCannotInferReturnType) closeScope(c) @@ -1534,16 +1534,16 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = var a = n.sons[0].sons[1] a.sons[i] = takeImplicitAddr(c, a.sons[i], false) else: - localError(n.sons[0].info, errXExpected, "tuple constructor") + localError(c.config, n.sons[0].info, errXExpected, "tuple constructor") else: discard proc semYield(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if c.p.owner == nil or c.p.owner.kind != skIterator: - localError(n.info, errYieldNotAllowedHere) + localError(c.config, n.info, errYieldNotAllowedHere) elif c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline: - localError(n.info, errYieldNotAllowedInTryStmt) + localError(c.config, n.info, errYieldNotAllowedInTryStmt) elif n.sons[0].kind != nkEmpty: n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility: var iterType = c.p.owner.typ @@ -1559,9 +1559,9 @@ proc semYield(c: PContext, n: PNode): PNode = semYieldVarResult(c, n, restype) else: - localError(n.info, errCannotReturnExpr) + localError(c.config, n.info, errCannotReturnExpr) elif c.p.owner.typ.sons[0] != nil: - localError(n.info, errGenerated, "yield statement must yield a value") + localError(c.config, n.info, errGenerated, "yield statement must yield a value") proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym = if onlyCurrentScope: @@ -1576,7 +1576,7 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = of nkDotExpr: result = nil if onlyCurrentScope: return - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope) if m != nil and m.kind == skModule: let ident = considerQuotedIdent(n[1], n) @@ -1591,16 +1591,16 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym else: - localError(n.info, errIdentifierExpected, renderTree(n)) + localError(c.config, n.info, errIdentifierExpected, renderTree(n)) result = nil proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) # we replace this node by a 'true' or 'false' node: result = newIntNode(nkIntLit, 0) - if not onlyCurrentScope and considerQuotedIdent(n[0], n).s == "defined": + if not onlyCurrentScope and considerQuotedIdent(c.config, n[0], n).s == "defined": if n.sons[1].kind != nkIdent: - localError(n.info, "obsolete usage of 'defined', use 'declared' instead") + localError(c.config, n.info, "obsolete usage of 'defined', use 'declared' instead") elif condsyms.isDefined(n.sons[1].ident): result.intVal = 1 elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: @@ -1618,12 +1618,12 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym = return errorSym(c, n[0]) if expandedSym.kind notin {skMacro, skTemplate}: - localError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s) + localError(c.config, n.info, errXisNoMacroOrTemplate, expandedSym.name.s) return errorSym(c, n[0]) result = expandedSym else: - localError(n.info, errXisNoMacroOrTemplate, n.renderTree) + localError(c.config, n.info, errXisNoMacroOrTemplate, n.renderTree) result = errorSym(c, n) proc expectString(c: PContext, n: PNode): string = @@ -1631,7 +1631,7 @@ proc expectString(c: PContext, n: PNode): string = if n.kind in nkStrKinds: return n.strVal else: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) proc getMagicSym(magic: TMagic): PSym = result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo) @@ -1668,9 +1668,9 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = inc cands symx = nextOverloadIter(o, c, headSymbol) if cands == 0: - localError(n.info, "expected a template that takes " & $(macroCall.len-1) & " arguments") + localError(c.config, n.info, "expected a template that takes " & $(macroCall.len-1) & " arguments") elif cands >= 2: - localError(n.info, "ambiguous symbol in 'getAst' context: " & $macroCall) + localError(c.config, n.info, "ambiguous symbol in 'getAst' context: " & $macroCall) else: let info = macroCall.sons[0].info macroCall.sons[0] = newSymNode(cand, info) @@ -1680,7 +1680,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = # we just perform overloading resolution here: #n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro}) else: - localError(n.info, "getAst takes a call, but got " & n.renderTree) + localError(c.config, n.info, "getAst takes a call, but got " & n.renderTree) # Preserve the magic symbol in order to be handled in evals.nim internalAssert n.sons[0].sym.magic == mExpandToAst #n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType @@ -1707,7 +1707,7 @@ proc processQuotations(n: var PNode, op: string, return if n.kind == nkPrefix: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) if n[0].kind == nkIdent: var examinedOp = n[0].ident.s if examinedOp == op: @@ -1734,7 +1734,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = # this will store the generated param names if quotedBlock.kind != nkStmtList: - localError(n.info, errXExpected, "block") + localError(c.config, n.info, errXExpected, "block") processQuotations(quotedBlock, op, quotes, ids) @@ -1829,7 +1829,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType; info: TLineInfo): PSym = let sym = magicsys.getCompilerProc("nimCreateFlowVar") if sym == nil: - localError(info, errSystemNeeds, "nimCreateFlowVar") + localError(c.config, info, errSystemNeeds, "nimCreateFlowVar") var bindings: TIdTable initIdTable(bindings) bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t) @@ -1858,10 +1858,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = n case s.magic # magics that need special treatment of mAddr: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) result = semAddr(c, n.sons[1], s.name.s == "unsafeAddr") of mTypeOf: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) result = semTypeOf(c, n.sons[1]) #of mArrGet: result = semArrGet(c, n, flags) #of mArrPut: result = semArrPut(c, n, flags) @@ -1878,12 +1878,12 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mExpandToAst: result = semExpandToAst(c, n, s, flags) of mQuoteAst: result = semQuoteAst(c, n) of mAstToStr: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) result.typ = getSysType(tyString) of mParallel: if parallel notin c.features: - localError(n.info, "use the {.experimental.} pragma to enable 'parallel'") + localError(c.config, n.info, "use the {.experimental.} pragma to enable 'parallel'") result = setMs(n, s) var x = n.lastSon if x.kind == nkDo: x = x.sons[bodyPos] @@ -1969,7 +1969,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = var it = n.sons[i] case it.kind of nkElifBranch, nkElifExpr: - checkSonsLen(it, 2) + checkSonsLen(it, 2, c.config) if whenNimvm: if semCheck: it.sons[1] = semExpr(c, it.sons[1]) @@ -1984,14 +1984,14 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = elif e.intVal != 0 and result == nil: setResult(it.sons[1]) of nkElse, nkElseExpr: - checkSonsLen(it, 1) + checkSonsLen(it, 1, c.config) if result == nil or whenNimvm: if semCheck: it.sons[0] = semExpr(c, it.sons[0]) typ = commonType(typ, it.sons[0].typ) if result == nil: result = it.sons[0] - else: illFormedAst(n) + else: illFormedAst(n, c.config) if result == nil: result = newNodeI(nkEmpty, n.info) if whenNimvm: result.typ = typ @@ -2010,7 +2010,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode = var typ: PType = nil for i in countup(0, sonsLen(n) - 1): if isRange(n.sons[i]): - checkSonsLen(n.sons[i], 3) + checkSonsLen(n.sons[i], 3, c.config) n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1]) n.sons[i].sons[2] = semExprWithType(c, n.sons[i].sons[2]) if typ == nil: @@ -2027,7 +2027,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode = if typ == nil: typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink}) if not isOrdinalType(typ): - localError(n.info, errOrdinalTypeExpected) + localError(c.config, n.info, errOrdinalTypeExpected) typ = makeRangeType(c, 0, MaxSetElements-1, n.info) elif lengthOrd(typ) > MaxSetElements: typ = makeRangeType(c, 0, MaxSetElements-1, n.info) @@ -2065,7 +2065,7 @@ proc semTableConstr(c: PContext, n: PNode): PNode = lastKey = i+1 - if lastKey != n.len: illFormedAst(n) + if lastKey != n.len: illFormedAst(n, c.config) result = semExpr(c, result) type @@ -2087,11 +2087,11 @@ proc checkPar(n: PNode): TParKind = if result == paTupleFields: if (n.sons[i].kind != nkExprColonExpr) or not (n.sons[i].sons[0].kind in {nkSym, nkIdent}): - localError(n.sons[i].info, errNamedExprExpected) + localError(c.config, n.sons[i].info, errNamedExprExpected) return paNone else: if n.sons[i].kind == nkExprColonExpr: - localError(n.sons[i].info, errNamedExprNotAllowed) + localError(c.config, n.sons[i].info, errNamedExprNotAllowed) return paNone proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = @@ -2101,12 +2101,12 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var ids = initIntSet() for i in countup(0, sonsLen(n) - 1): if n[i].kind != nkExprColonExpr or n[i][0].kind notin {nkSym, nkIdent}: - illFormedAst(n.sons[i]) + illFormedAst(n.sons[i], c.config) var id: PIdent if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident else: id = n.sons[i].sons[0].sym.name if containsOrIncl(ids, id.id): - localError(n.sons[i].info, errFieldInitTwice, id.s) + localError(c.config, n.sons[i].info, errFieldInitTwice, id.s) n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1], flags*{efAllowDestructor}) var f = newSymS(skField, n.sons[i].sons[0], c) @@ -2140,7 +2140,7 @@ include semobjconstr proc semBlock(c: PContext, n: PNode): PNode = result = n inc(c.p.nestedBlockCounter) - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) openScope(c) # BUGFIX: label is in the scope of block! if n.sons[0].kind != nkEmpty: var labl = newSymG(skLabel, n.sons[0], c) @@ -2164,7 +2164,7 @@ proc semExport(c: PContext, n: PNode): PNode = var o: TOverloadIter var s = initOverloadIter(o, c, a) if s == nil: - localError(a.info, errGenerated, "cannot export: " & renderTree(a)) + localError(c.config, a.info, errGenerated, "cannot export: " & renderTree(a)) elif s.kind == skModule: # forward everything from that module: strTableAdd(c.module.tab, s) @@ -2217,7 +2217,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.kind == nkSym: markIndirect(c, result.sym) # if isGenericRoutine(result.sym): - # localError(n.info, errInstantiateXExplicitly, s.name.s) + # localError(c.config, n.info, errInstantiateXExplicitly, s.name.s) of nkSym: # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! @@ -2277,7 +2277,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result.typ = makeTypeDesc(c, typ) of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) #when defined(nimsuggest): # if gIdeCmd == ideCon and gTrackPos == n.info: suggestExprNoCheck(c, n) let mode = if nfDotField in n.flags: {} else: {checkUndeclared} @@ -2333,7 +2333,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = else: result = semExpr(c, result, flags) of nkBracketExpr: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) result = semArrayAccess(c, n, flags) of nkCurlyExpr: result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags) @@ -2372,24 +2372,24 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkDerefExpr: result = semDeref(c, n) of nkAddr: result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) result = semAddr(c, n.sons[0]) of nkHiddenAddr, nkHiddenDeref: - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) n.sons[0] = semExpr(c, n.sons[0], flags) of nkCast: result = semCast(c, n) of nkIfExpr, nkIfStmt: result = semIf(c, n) of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) considerGenSyms(c, n) of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv: - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) considerGenSyms(c, n) of nkChckRangeF, nkChckRange64, nkChckRange: - checkSonsLen(n, 3) + checkSonsLen(n, 3, c.config) considerGenSyms(c, n) of nkCheckedFieldExpr: - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) considerGenSyms(c, n) of nkTableConstr: result = semTableConstr(c, n) @@ -2433,19 +2433,19 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # # works: if c.currentScope.depthLevel > 2 + c.compilesContextId: - localError(n.info, errXOnlyAtModuleScope, "import") + localError(c.config, n.info, errXOnlyAtModuleScope, "import") result = evalImport(c, n) of nkImportExceptStmt: - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "import") result = evalImportExcept(c, n) of nkFromStmt: - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "from") result = evalFrom(c, n) of nkIncludeStmt: - #if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include") + #if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "include") result = evalInclude(c, n) of nkExportStmt, nkExportExceptStmt: - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "export") result = semExport(c, n) of nkPragmaBlock: result = semPragmaBlock(c, n) @@ -2454,14 +2454,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkDefer: n.sons[0] = semExpr(c, n.sons[0]) if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]): - localError(n.info, errGenerated, "'defer' takes a 'void' expression") - #localError(n.info, errGenerated, "'defer' not allowed in this context") + localError(c.config, n.info, errGenerated, "'defer' takes a 'void' expression") + #localError(c.config, n.info, errGenerated, "'defer' not allowed in this context") of nkGotoState, nkState: - if n.len != 1 and n.len != 2: illFormedAst(n) + if n.len != 1 and n.len != 2: illFormedAst(n, c.config) for i in 0 ..< n.len: n.sons[i] = semExpr(c, n.sons[i]) of nkComesFrom: discard "ignore the comes from information for now" else: - localError(n.info, errInvalidExpressionX, + localError(c.config, n.info, errInvalidExpressionX, renderTree(n, {renderNoComments})) if result != nil: incl(result.flags, nfSem) diff --git a/compiler/semfields.nim b/compiler/semfields.nim index c5bc07d77f..70efe8c4cc 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -47,7 +47,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = break else: if n.kind == nkContinueStmt: - localError(n.info, errGenerated, + localError(c.config, n.info, errGenerated, "'continue' not supported in a 'fields' loop") result = copyNode(n) newSons(result, sonsLen(n)) @@ -76,7 +76,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = let L = forLoop.len let call = forLoop.sons[L-2] if call.len > 2: - localError(forLoop.info, errGenerated, + localError(c.config, forLoop.info, errGenerated, "parallel 'fields' iterator does not work for 'case' objects") return # iterate over the selector: @@ -107,7 +107,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = result = newNodeI(nkWhileStmt, n.info, 2) var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true") if trueSymbol == nil: - localError(n.info, errSystemNeeds, "true") + localError(c.config, n.info, errSystemNeeds, "true") trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(c), n.info) trueSymbol.typ = getSysType(tyBool) @@ -118,13 +118,13 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = var length = sonsLen(n) var call = n.sons[length-2] if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs): - localError(n.info, errWrongNumberOfVariables) + localError(c.config, n.info, errWrongNumberOfVariables) return result const skippedTypesForFields = abstractVar - {tyTypeDesc} + tyUserTypeClasses var tupleTypeA = skipTypes(call.sons[1].typ, skippedTypesForFields) if tupleTypeA.kind notin {tyTuple, tyObject}: - localError(n.info, errGenerated, "no object or tuple type") + localError(c.config, n.info, errGenerated, "no object or tuple type") return result for i in 1..call.len-1: var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 32b3853089..60c655bba4 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -54,10 +54,13 @@ proc pushProcCon*(c: PContext; owner: PSym) = rawPushProcCon(c, owner) rawHandleSelf(c, owner) +const + errCannotInstantiateX = "cannot instantiate: '$1'" + iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym = - internalAssert n.kind == nkGenericParams + internalAssert c.config, n.kind == nkGenericParams for i, a in n.pairs: - internalAssert a.kind == nkSym + internalAssert c.config, a.kind == nkSym var q = a.sym if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses: continue @@ -71,10 +74,10 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym # later by semAsgn in return type inference scenario t = q.typ else: - localError(a.info, errCannotInstantiateX, s.name.s) + localError(c.config, a.info, errCannotInstantiateX & s.name.s) t = errorType(c) elif t.kind == tyGenericParam: - localError(a.info, errCannotInstantiateX, q.name.s) + localError(c.config, a.info, errCannotInstantiateX & q.name.s) t = errorType(c) elif t.kind == tyGenericInvocation: #t = instGenericContainer(c, a, t) @@ -145,7 +148,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) = freshGenSyms(b, result, orig, symMap) b = semProcBody(c, b) b = hloBody(c, b) - n.sons[bodyPos] = transformBody(c.module, b, result) + n.sons[bodyPos] = transformBody(c.graph, c.module, b, result) #echo "code instantiated ", result.name.s excl(result.flags, sfForward) dec c.inGenericInst @@ -174,7 +177,7 @@ proc sideEffectsCheck(c: PContext, s: PSym) = proc instGenericContainer(c: PContext, info: TLineInfo, header: PType, allowMetaTypes = false): PType = - internalAssert header.kind == tyGenericInvocation + internalAssert c.config, header.kind == tyGenericInvocation var typeMap: LayeredIdTable @@ -199,7 +202,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType, var param: PSym template paramSym(kind): untyped = - newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info) + newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info) if genParam.kind == tyStatic: param = paramSym skConst @@ -233,14 +236,12 @@ proc instantiateProcType(c: PContext, pt: TIdTable, # at this point semtypinst have to become part of sem, because it # will need to use openScope, addDecl, etc. #addDecl(c, prc) - pushInfoContext(info) var typeMap = initLayeredTypeMap(pt) var cl = initTypeVars(c, addr(typeMap), info, nil) var result = instCopyType(cl, prc.typ) let originalParams = result.n result.n = originalParams.shallowCopy - for i in 1 ..< result.len: # twrong_field_caching requires these 'resetIdTable' calls: if i > 1: @@ -248,7 +249,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable, resetIdTable(cl.localCache) result.sons[i] = replaceTypeVarsT(cl, result.sons[i]) propagateToOwner(result, result.sons[i]) - internalAssert originalParams[i].kind == nkSym + internalAssert c.config, originalParams[i].kind == nkSym when true: let oldParam = originalParams[i].sym let param = copySym(oldParam) @@ -285,9 +286,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, ## The `pt` parameter is a type-unsafe mapping table used to link generic ## parameters to their concrete types within the generic instance. # no need to instantiate generic templates/macros: - internalAssert fn.kind notin {skMacro, skTemplate} + internalAssert c.config, fn.kind notin {skMacro, skTemplate} # generates an instantiated proc - if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep") + if c.instCounter > 1000: internalError(c.config, fn.ast.info, "nesting too deep") inc(c.instCounter) # careful! we copy the whole AST including the possibly nil body! var n = copyTree(fn.ast) @@ -306,7 +307,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, openScope(c) let gp = n.sons[genericParamsPos] - internalAssert gp.kind != nkEmpty + internalAssert c.config, gp.kind != nkEmpty n.sons[namePos] = newSymNode(result) pushInfoContext(info) var entry = TInstantiation.new diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 3f0df00650..49dfb58f91 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -16,7 +16,7 @@ proc semAddr(c: PContext; n: PNode; isUnsafeAddr=false): PNode = if x.kind == nkSym: x.sym.flags.incl(sfAddrTaken) if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}: - localError(n.info, errExprHasNoAddress) + localError(c.config, n.info, errExprHasNoAddress) result.add x result.typ = makePtrType(c, x.typ) @@ -43,7 +43,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode = let x = copyTree(n) x.sons[0] = newIdentNode(getIdent"[]", n.info) bracketNotFoundError(c, x) - #localError(n.info, "could not resolve: " & $n) + #localError(c.config, n.info, "could not resolve: " & $n) result = n proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode = @@ -70,7 +70,7 @@ proc expectIntLit(c: PContext, n: PNode): int = let x = c.semConstExpr(c, n) case x.kind of nkIntLit..nkInt64Lit: result = int(x.intVal) - else: localError(n.info, errIntLiteralExpected) + else: localError(c.config, n.info, errIntLiteralExpected) proc semInstantiationInfo(c: PContext, n: PNode): PNode = result = newNodeIT(nkTupleConstr, n.info, n.typ) @@ -140,7 +140,7 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode = of "genericHead": var res = uninstantiate(operand) if res == operand and res.kind notin tyMagicGenerics: - localError(traitCall.info, + localError(c.config, traitCall.info, "genericHead expects a generic type. The given type was " & typeToString(operand)) return newType(tyError, context).toNode(traitCall.info) @@ -153,7 +153,7 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode = hasDestructor(t) result = newIntNodeT(ord(not complexObj), traitCall) else: - localError(traitCall.info, "unknown trait") + localError(c.config, traitCall.info, "unknown trait") result = emptyNode proc semTypeTraits(c: PContext, n: PNode): PNode = @@ -176,7 +176,7 @@ proc semOrd(c: PContext, n: PNode): PNode = elif parType.kind == tySet: result.typ = makeRangeType(c, firstOrd(parType), lastOrd(parType), n.info) else: - localError(n.info, errOrdinalTypeExpected) + localError(c.config, n.info, errOrdinalTypeExpected) result.typ = errorType(c) proc semBindSym(c: PContext, n: PNode): PNode = @@ -185,13 +185,13 @@ proc semBindSym(c: PContext, n: PNode): PNode = let sl = semConstExpr(c, n.sons[1]) if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}: - localError(n.sons[1].info, errStringLiteralExpected) + localError(c.config, n.sons[1].info, errStringLiteralExpected) return errorNode(c, n) let isMixin = semConstExpr(c, n.sons[2]) if isMixin.kind != nkIntLit or isMixin.intVal < 0 or isMixin.intVal > high(TSymChoiceRule).int: - localError(n.sons[2].info, errConstExprExpected) + localError(c.config, n.sons[2].info, errConstExprExpected) return errorNode(c, n) let id = newIdentNode(getIdent(sl.strVal), n.info) @@ -221,9 +221,9 @@ proc semOf(c: PContext, n: PNode): PNode = let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc}) if x.kind == tyTypeDesc or y.kind != tyTypeDesc: - localError(n.info, errXExpectsObjectTypes, "of") + localError(c.config, n.info, errXExpectsObjectTypes, "of") elif b.kind != tyObject or a.kind != tyObject: - localError(n.info, errXExpectsObjectTypes, "of") + localError(c.config, n.info, errXExpectsObjectTypes, "of") else: let diff = inheritanceDiff(a, b) # | returns: 0 iff `a` == `b` @@ -238,9 +238,9 @@ proc semOf(c: PContext, n: PNode): PNode = result.typ = getSysType(tyBool) return result elif diff == high(int): - localError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a)) + localError(c.config, n.info, errXcanNeverBeOfThisSubtype, typeToString(a)) else: - localError(n.info, errXExpectsTwoArguments, "of") + localError(c.config, n.info, errXExpectsTwoArguments, "of") n.typ = getSysType(tyBool) result = n @@ -277,11 +277,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mDotDot: result = n of mRoof: - localError(n.info, "builtin roof operator is not supported anymore") + localError(c.config, n.info, "builtin roof operator is not supported anymore") of mPlugin: let plugin = getPlugin(n[0].sym) if plugin.isNil: - localError(n.info, "cannot find plugin " & n[0].sym.name.s) + localError(c.config, n.info, "cannot find plugin " & n[0].sym.name.s) result = n else: result = plugin(c, n) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index cfa0fbd051..a47bc24ed3 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -41,9 +41,9 @@ proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) = proc invalidObjConstr(n: PNode) = if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s[0] == ':': - localError(n.info, "incorrect object construction syntax; use a space after the colon") + localError(c.config, n.info, "incorrect object construction syntax; use a space after the colon") else: - localError(n.info, "incorrect object construction syntax") + localError(c.config, n.info, "incorrect object construction syntax") proc locateFieldInInitExpr(field: PSym, initExpr: PNode): PNode = # Returns the assignment nkExprColonExpr node or nil @@ -63,7 +63,7 @@ proc semConstrField(c: PContext, flags: TExprFlags, if assignment != nil: if nfSem in assignment.flags: return assignment[1] if not fieldVisible(c, field): - localError(initExpr.info, + localError(c.config, initExpr.info, "the field '$1' is not accessible.", [field.name.s]) return @@ -130,7 +130,7 @@ proc missingMandatoryFields(fieldsRecList, initExpr: PNode): string = proc checkForMissingFields(recList, initExpr: PNode) = let missing = missingMandatoryFields(recList, initExpr) if missing != nil: - localError(initExpr.info, "fields not initialized: $1.", [missing]) + localError(c.config, initExpr.info, "fields not initialized: $1.", [missing]) proc semConstructFields(c: PContext, recNode: PNode, initExpr: PNode, flags: TExprFlags): InitStatus = @@ -164,7 +164,7 @@ proc semConstructFields(c: PContext, recNode: PNode, if selectedBranch != -1: let prevFields = fieldsPresentInBranch(selectedBranch) let currentFields = fieldsPresentInBranch(i) - localError(initExpr.info, + localError(c.config, initExpr.info, "The fields ($1) and ($2) cannot be initialized together, " & "because they are from conflicting branches in the case object.", [prevFields, currentFields]) @@ -179,7 +179,7 @@ proc semConstructFields(c: PContext, recNode: PNode, discriminator.sym, initExpr) if discriminatorVal == nil: let fields = fieldsPresentInBranch(selectedBranch) - localError(initExpr.info, + localError(c.config, initExpr.info, "you must provide a compile-time value for the discriminator '$1' " & "in order to prove that it's safe to initialize $2.", [discriminator.sym.name.s, fields]) @@ -189,7 +189,7 @@ proc semConstructFields(c: PContext, recNode: PNode, template wrongBranchError(i) = let fields = fieldsPresentInBranch(i) - localError(initExpr.info, + localError(c.config, initExpr.info, "a case selecting discriminator '$1' with value '$2' " & "appears in the object construction, but the field(s) $3 " & "are in conflict with this value.", @@ -263,13 +263,13 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = for child in n: result.add child if t == nil: - localError(n.info, errGenerated, "object constructor needs an object type") + localError(c.config, n.info, errGenerated, "object constructor needs an object type") return t = skipTypes(t, {tyGenericInst, tyAlias, tySink}) if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink}) if t.kind != tyObject: - localError(n.info, errGenerated, "object constructor needs an object type") + localError(c.config, n.info, errGenerated, "object constructor needs an object type") return # Check if the object is fully initialized by recursively testing each @@ -304,9 +304,9 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = for j in 1 ..< i: let prevId = considerQuotedIdent(result[j][0]) if prevId.id == id.id: - localError(field.info, errFieldInitTwice, id.s) + localError(c.config, field.info, errFieldInitTwice, id.s) return # 2) No such field exists in the constructed type - localError(field.info, errUndeclaredFieldX, id.s) + localError(c.config, field.info, errUndeclaredFieldX, id.s) return diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b0bd4e0f61..f1a34785b7 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -14,22 +14,22 @@ var enforceVoidContext = PType(kind: tyStmt) proc semDiscard(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if n.sons[0].kind != nkEmpty: n.sons[0] = semExprWithType(c, n.sons[0]) if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone or n.sons[0].kind == nkTypeOfExpr: - localError(n.info, errInvalidDiscard) + localError(c.config, n.info, errInvalidDiscard) proc semBreakOrContinue(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if n.sons[0].kind != nkEmpty: if n.kind != nkContinueStmt: var s: PSym case n.sons[0].kind of nkIdent: s = lookUp(c, n.sons[0]) of nkSym: s = n.sons[0].sym - else: illFormedAst(n) + else: illFormedAst(n, c.config) s = getGenSym(c, s) if s.kind == skLabel and s.owner.id == c.p.owner.id: var x = newSymNode(s) @@ -39,22 +39,22 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = suggestSym(x.info, s, c.graph.usageSym) styleCheckUse(x.info, s) else: - localError(n.info, errInvalidControlFlowX, s.name.s) + localError(c.config, n.info, errInvalidControlFlowX, s.name.s) else: - localError(n.info, errGenerated, "'continue' cannot have a label") + localError(c.config, n.info, errGenerated, "'continue' cannot have a label") elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): - localError(n.info, errInvalidControlFlowX, + localError(c.config, n.info, errInvalidControlFlowX, renderTree(n, {renderNoComments})) proc semAsm(con: PContext, n: PNode): PNode = - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) var marker = pragmaAsm(con, n.sons[0]) if marker == '\0': marker = '`' # default marker result = semAsmOrEmit(con, n, marker) proc semWhile(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) openScope(c) n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0])) inc(c.p.nestedLoopCounter) @@ -98,7 +98,7 @@ proc implicitlyDiscardable(n: PNode): bool = proc fixNilType(n: PNode) = if isAtom(n): if n.kind != nkNilLit and n.typ != nil: - localError(n.info, errDiscardValueX, n.typ.typeToString) + localError(c.config, n.info, errDiscardValueX, n.typ.typeToString) elif n.kind in {nkStmtList, nkStmtListExpr}: n.kind = nkStmtList for it in n: fixNilType(it) @@ -123,7 +123,7 @@ proc discardCheck(c: PContext, result: PNode) = s.add "; start of expression here: " & $result.info if result.typ.kind == tyProc: s.add "; for a function call use ()" - localError(n.info, s) + localError(c.config, n.info, s) proc semIf(c: PContext, n: PNode): PNode = result = n @@ -142,7 +142,7 @@ proc semIf(c: PContext, n: PNode): PNode = hasElse = true it.sons[0] = semExprBranchScope(c, it.sons[0]) typ = commonType(typ, it.sons[0]) - else: illFormedAst(it) + else: illFormedAst(it, c.config) if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: for it in n: discardCheck(c, it.lastSon) result.kind = nkIfStmt @@ -158,7 +158,7 @@ proc semIf(c: PContext, n: PNode): PNode = proc semCase(c: PContext, n: PNode): PNode = result = n - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) openScope(c) n.sons[0] = semExprWithType(c, n.sons[0]) var chckCovered = false @@ -172,7 +172,7 @@ proc semCase(c: PContext, n: PNode): PNode = of tyFloat..tyFloat128, tyString, tyError: discard else: - localError(n.info, errSelectorMustBeOfCertainTypes) + localError(c.config, n.info, errSelectorMustBeOfCertainTypes) return for i in countup(1, sonsLen(n) - 1): var x = n.sons[i] @@ -181,14 +181,14 @@ proc semCase(c: PContext, n: PNode): PNode = suggestEnum(c, x, caseTyp) case x.kind of nkOfBranch: - checkMinSonsLen(x, 2) + checkMinSonsLen(x, 2, c.config) semCaseBranch(c, n, x, i, covered) var last = sonsLen(x)-1 x.sons[last] = semExprBranchScope(c, x.sons[last]) typ = commonType(typ, x.sons[last]) of nkElifBranch: chckCovered = false - checkSonsLen(x, 2) + checkSonsLen(x, 2, c.config) when newScopeForIf: openScope(c) x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0])) when not newScopeForIf: openScope(c) @@ -197,17 +197,17 @@ proc semCase(c: PContext, n: PNode): PNode = closeScope(c) of nkElse: chckCovered = false - checkSonsLen(x, 1) + checkSonsLen(x, 1, c.config) x.sons[0] = semExprBranchScope(c, x.sons[0]) typ = commonType(typ, x.sons[0]) hasElse = true else: - illFormedAst(x) + illFormedAst(x, c.config) if chckCovered: if covered == toCover(n.sons[0].typ): hasElse = true else: - localError(n.info, errNotAllCasesCovered) + localError(c.config, n.info, errNotAllCasesCovered) closeScope(c) if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) @@ -232,16 +232,16 @@ proc semTry(c: PContext, n: PNode): PNode = if isImportedException(typ): is_imported = true elif not isException(typ): - localError(typeNode.info, errExprCannotBeRaised) + localError(c.config, typeNode.info, errExprCannotBeRaised) if containsOrIncl(check, typ.id): - localError(typeNode.info, errExceptionAlreadyHandled) + localError(c.config, typeNode.info, errExceptionAlreadyHandled) typeNode = newNodeIT(nkType, typeNode.info, typ) is_imported result = n inc c.p.inTryStmt - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) var typ = commonTypeBegin n[0] = semExprBranchScope(c, n[0]) @@ -250,7 +250,7 @@ proc semTry(c: PContext, n: PNode): PNode = var last = sonsLen(n) - 1 for i in countup(1, last): let a = n.sons[i] - checkMinSonsLen(a, 1) + checkMinSonsLen(a, 1, c.config) openScope(c) if a.kind == nkExceptBranch: @@ -277,10 +277,10 @@ proc semTry(c: PContext, n: PNode): PNode = else: is_native = true if is_native and is_imported: - localError(a[0].info, "Mix of imported and native exception types is not allowed in one except branch") + localError(c.config, a[0].info, "Mix of imported and native exception types is not allowed in one except branch") elif a.kind != nkFinally: - illFormedAst(n) + illFormedAst(n, c.config) # last child of an nkExcept/nkFinally branch is a statement: a[^1] = semExprBranchScope(c, a[^1]) @@ -339,7 +339,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = result = semIdentWithPragma(c, kind, n, {}) if result.owner.kind == skModule: incl(result.flags, sfGlobal) - suggestSym(n.info, result, c.graph.usageSym) + suggestSym(c.config, n.info, result, c.graph.usageSym) styleCheckDef(result) proc checkNilable(v: PSym) = @@ -369,13 +369,13 @@ proc isDiscardUnderscore(v: PSym): bool = proc semUsing(c: PContext; n: PNode): PNode = result = ast.emptyNode - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "using") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "using") for i in countup(0, sonsLen(n)-1): var a = n.sons[i] if gCmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue - if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a) - checkMinSonsLen(a, 3) + if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var length = sonsLen(a) if a.sons[length-2].kind != nkEmpty: let typ = semTypeNode(c, a.sons[length-2], nil) @@ -384,10 +384,10 @@ proc semUsing(c: PContext; n: PNode): PNode = v.typ = typ strTableIncl(c.signatures, v) else: - localError(a.info, "'using' section must have a type") + localError(c.config, a.info, "'using' section must have a type") var def: PNode if a.sons[length-1].kind != nkEmpty: - localError(a.info, "'using' sections cannot contain assignments") + localError(c.config, a.info, "'using' sections cannot contain assignments") proc hasEmpty(typ: PType): bool = if typ.kind in {tySequence, tyArray, tySet}: @@ -416,7 +416,7 @@ proc makeDeref(n: PNode): PNode = proc fillPartialObject(c: PContext; n: PNode; typ: PType) = if n.len == 2: let x = semExprWithType(c, n[0]) - let y = considerQuotedIdent(n[1]) + let y = considerQuotedIdent(c.config, n[1]) let obj = x.typ.skipTypes(abstractPtrs) if obj.kind == tyObject and tfPartial in obj.flags: let field = newSym(skField, getIdent(y.s), obj.sym, n[1].info) @@ -427,14 +427,14 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) = n.sons[1] = newSymNode(field) n.typ = field.typ else: - localError(n.info, "implicit object field construction " & + localError(c.config, n.info, "implicit object field construction " & "requires a .partial object, but got " & typeToString(obj)) else: - localError(n.info, "nkDotNode requires 2 children") + localError(c.config, n.info, "nkDotNode requires 2 children") proc setVarType(v: PSym, typ: PType) = if v.typ != nil and not sameTypeOrNil(v.typ, typ): - localError(v.info, "inconsistent typing for reintroduced symbol '" & + localError(c.config, v.info, "inconsistent typing for reintroduced symbol '" & v.name.s & "': previous type was: " & typeToString(v.typ) & "; new type is: " & typeToString(typ)) v.typ = typ @@ -447,8 +447,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var a = n.sons[i] if gCmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue - if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a) - checkMinSonsLen(a, 3) + if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var length = sonsLen(a) var typ: PType if a.sons[length-2].kind != nkEmpty: @@ -460,7 +460,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = def = semExprWithType(c, a.sons[length-1], {efAllowDestructor}) if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro: # prevent the all too common 'var x = int' bug: - localError(def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?") + localError(c.config, def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?") def.typ = errorType(c) if typ != nil: if typ.isMetaType: @@ -476,12 +476,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass: typ = typ.lastSon if hasEmpty(typ): - localError(def.info, errCannotInferTypeOfTheLiteral, + localError(c.config, def.info, errCannotInferTypeOfTheLiteral, ($typ.kind).substr(2).toLowerAscii) elif typ.kind == tyProc and tfUnresolved in typ.flags: - localError(def.info, errProcHasNoConcreteType, def.renderTree) + localError(c.config, def.info, errProcHasNoConcreteType, def.renderTree) else: - if symkind == skLet: localError(a.info, errLetNeedsInit) + if symkind == skLet: localError(c.config, a.info, errLetNeedsInit) # this can only happen for errornous var statements: if typ == nil: continue @@ -490,9 +490,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink}) if a.kind == nkVarTuple: if tup.kind != tyTuple: - localError(a.info, errXExpected, "tuple") + localError(c.config, a.info, errXExpected, "tuple") elif length-2 != sonsLen(tup): - localError(a.info, errWrongNumberOfVariables) + localError(c.config, a.info, errWrongNumberOfVariables) b = newNodeI(nkVarTuple, a.info) newSons(b, length) b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator @@ -527,10 +527,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if def.kind != nkEmpty: # this is needed for the evaluation pass and for the guard checking: v.ast = def - if sfThread in v.flags: localError(def.info, errThreadvarCannotInit) + if sfThread in v.flags: localError(c.config, def.info, errThreadvarCannotInit) setVarType(v, typ) b = newNodeI(nkIdentDefs, a.info) - if importantComments(): + if importantComments(c.config): # keep documentation information: b.comment = a.comment addSon(b, newSymNode(v)) @@ -554,15 +554,15 @@ proc semConst(c: PContext, n: PNode): PNode = var a = n.sons[i] if gCmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue - if (a.kind != nkConstDef): illFormedAst(a) - checkSonsLen(a, 3) + if a.kind != nkConstDef: illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) var v = semIdentDef(c, a.sons[0], skConst) var typ: PType = nil if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil) var def = semConstExpr(c, a.sons[2]) if def == nil: - localError(a.sons[2].info, errConstExprExpected) + localError(c.config, a.sons[2].info, errConstExprExpected) continue # check type compatibility between def.typ and typ: if typ != nil: @@ -570,10 +570,10 @@ proc semConst(c: PContext, n: PNode): PNode = else: typ = def.typ if typ == nil: - localError(a.sons[2].info, errConstExprExpected) + localError(c.config, a.sons[2].info, errConstExprExpected) continue if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit: - localError(a.info, "invalid type for const: " & typeToString(typ)) + localError(c.config, a.info, "invalid type for const: " & typeToString(typ)) continue setVarType(v, typ) v.ast = def # no need to copy @@ -619,9 +619,9 @@ proc semForVars(c: PContext, n: PNode): PNode = n.sons[0] = newSymNode(v) if sfGenSym notin v.flags: addForVarDecl(c, v) else: - localError(n.info, errWrongNumberOfVariables) + localError(c.config, n.info, errWrongNumberOfVariables) elif length-2 != sonsLen(iter): - localError(n.info, errWrongNumberOfVariables) + localError(c.config, n.info, errWrongNumberOfVariables) else: for i in countup(0, length - 3): var v = symForVar(c, n.sons[i]) @@ -671,7 +671,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode = if match == nil: match = symx else: - localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [ + localError(c.config, n.info, errAmbiguousCallXYZ % [ getProcHeader(match), getProcHeader(symx), $iterExpr]) symx = nextOverloadIter(o, c, headSymbol) @@ -685,7 +685,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode = else: result = nil proc semFor(c: PContext, n: PNode): PNode = - checkMinSonsLen(n, 3) + checkMinSonsLen(n, 3, c.config) var length = sonsLen(n) result = handleForLoopMacro(c, n) if result != nil: return result @@ -715,7 +715,7 @@ proc semFor(c: PContext, n: PNode): PNode = elif length == 4: n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2]) else: - localError(n.sons[length-2].info, errIteratorExpected) + localError(c.config, n.sons[length-2].info, errIteratorExpected) result = semForVars(c, n) else: result = semForVars(c, n) @@ -726,31 +726,31 @@ proc semFor(c: PContext, n: PNode): PNode = proc semRaise(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if n[0].kind != nkEmpty: n[0] = semExprWithType(c, n[0]) let typ = n[0].typ if not isImportedException(typ): if typ.kind != tyRef or typ.lastSon.kind != tyObject: - localError(n.info, errExprCannotBeRaised) + localError(c.config, n.info, errExprCannotBeRaised) if not isException(typ.lastSon): - localError(n.info, "raised object of type $1 does not inherit from Exception", + localError(c.config, n.info, "raised object of type $1 does not inherit from Exception", [typeToString(typ)]) proc addGenericParamListToScope(c: PContext, n: PNode) = - if n.kind != nkGenericParams: illFormedAst(n) + if n.kind != nkGenericParams: illFormedAst(n, c.config) for i in countup(0, sonsLen(n)-1): var a = n.sons[i] if a.kind == nkSym: addDecl(c, a.sym) - else: illFormedAst(a) + else: illFormedAst(a, c.config) proc typeSectionTypeName(n: PNode): PNode = if n.kind == nkPragmaExpr: - if n.len == 0: illFormedAst(n) + if n.len == 0: illFormedAst(n, c.config) result = n.sons[0] else: result = n - if result.kind != nkSym: illFormedAst(n) + if result.kind != nkSym: illFormedAst(n, c.config) proc typeSectionLeftSidePass(c: PContext, n: PNode) = @@ -764,16 +764,16 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = suggestStmt(c, a) dec c.inTypeContext if a.kind == nkCommentStmt: continue - if a.kind != nkTypeDef: illFormedAst(a) - checkSonsLen(a, 3) + if a.kind != nkTypeDef: illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) let name = a.sons[0] var s: PSym if name.kind == nkDotExpr and a[2].kind == nkObjectTy: - let pkgName = considerQuotedIdent(name[0]) - let typName = considerQuotedIdent(name[1]) + let pkgName = considerQuotedIdent(c.config, name[0]) + let typName = considerQuotedIdent(c.config, name[1]) let pkg = c.graph.packageSyms.strTableGet(pkgName) if pkg.isNil or pkg.kind != skPackage: - localError(name.info, "unknown package name: " & pkgName.s) + localError(c.config, name.info, "unknown package name: " & pkgName.s) else: let typsym = pkg.tab.strTableGet(typName) if typsym.isNil: @@ -787,7 +787,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = s = typsym addInterfaceDecl(c, s) else: - localError(name.info, typsym.name.s & " is not a type that can be forwarded") + localError(c.config, name.info, typsym.name.s & " is not a type that can be forwarded") s = typsym else: s = semIdentDef(c, name, skType) @@ -799,7 +799,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = # check if the symbol already exists: let pkg = c.module.owner if not isTopLevel(c) or pkg.isNil: - localError(name.info, "only top level types in a package can be 'package'") + localError(c.config, name.info, "only top level types in a package can be 'package'") else: let typsym = pkg.tab.strTableGet(s.name) if typsym != nil: @@ -807,7 +807,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = typeCompleted(typsym) typsym.info = s.info else: - localError(name.info, "cannot complete type '" & s.name.s & "' twice; " & + localError(c.config, name.info, "cannot complete type '" & s.name.s & "' twice; " & "previous type completion was here: " & $typsym.info) s = typsym # add it here, so that recursive types are possible: @@ -822,7 +822,7 @@ proc checkCovariantParamsUsages(genericType: PType) = var body = genericType[^1] proc traverseSubTypes(t: PType): bool = - template error(msg) = localError(genericType.sym.info, msg) + template error(msg) = localError(c.config, genericType.sym.info, msg) result = false @@ -903,12 +903,12 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = 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) + if a.kind != nkTypeDef: illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) let name = typeSectionTypeName(a.sons[0]) var s = name.sym if s.magic == mNone and a.sons[2].kind == nkEmpty: - localError(a.info, errImplOfXexpected, s.name.s) + localError(c.config, a.info, errImplOfXexpected, s.name.s) if s.magic != mNone: processMagicType(c, s) if a.sons[1].kind != nkEmpty: # We have a generic type declaration here. In generic types, @@ -986,7 +986,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = proc checkForMetaFields(n: PNode) = template checkMeta(t) = if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags: - localError(n.info, errTIsNotAConcreteType, t.typeToString) + localError(c.config, n.info, errTIsNotAConcreteType, t.typeToString) if n.isNil: return case n.kind @@ -1045,7 +1045,7 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode = var f = checkModuleName(n.sons[i]) if f != InvalidFileIDX: if containsOrIncl(c.includedFiles, f.int): - localError(n.info, errRecursiveDependencyX, f.toFilename) + localError(c.config, n.info, errRecursiveDependencyX, f.toFilename) else: let code = gIncludeFile(c.graph, c.module, f, c.cache) gatherStmts c, code, result @@ -1101,12 +1101,12 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) = s.typ = semProcTypeNode(c, n, genericParams, nil, s.kind) if s.kind notin {skMacro, skTemplate}: if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt: - localError(n.info, errGenerated, "invalid return type: 'stmt'") + localError(c.config, n.info, "invalid return type: 'stmt'") proc addParams(c: PContext, n: PNode, kind: TSymKind) = for i in countup(1, sonsLen(n)-1): if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind) - else: illFormedAst(n) + else: illFormedAst(n, c.config) proc semBorrow(c: PContext, n: PNode, s: PSym) = # search for the correct alias: @@ -1115,7 +1115,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) = # store the alias: n.sons[bodyPos] = newSymNode(b) else: - localError(n.info, errNoSymbolToBorrowFromFound) + localError(c.config, n.info, errNoSymbolToBorrowFromFound) proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = if t != nil: @@ -1138,7 +1138,7 @@ proc lookupMacro(c: PContext, n: PNode): PSym = result = n.sym if result.kind notin {skMacro, skTemplate}: result = nil else: - result = searchInScopes(c, considerQuotedIdent(n), {skMacro, skTemplate}) + result = searchInScopes(c, considerQuotedIdent(c.config, n), {skMacro, skTemplate}) proc semProcAnnotation(c: PContext, prc: PNode; validPragmas: TSpecialWords): PNode = @@ -1150,11 +1150,11 @@ proc semProcAnnotation(c: PContext, prc: PNode; let m = lookupMacro(c, key) if m == nil: if key.kind == nkIdent and key.ident.id == ord(wDelegator): - if considerQuotedIdent(prc.sons[namePos]).s == "()": + if considerQuotedIdent(c.config, prc.sons[namePos]).s == "()": prc.sons[namePos] = newIdentNode(c.cache.idDelegator, prc.info) prc.sons[pragmasPos] = copyExcept(n, i) else: - localError(prc.info, errOnlyACallOpCanBeDelegator) + localError(c.config, prc.info, errOnlyACallOpCanBeDelegator) continue elif sfCustomPragma in m.flags: continue # semantic check for custom pragma happens later in semProcAux @@ -1199,7 +1199,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = result = semProcAnnotation(c, n, lambdaPragmas) if result != nil: return result result = n - checkSonsLen(n, bodyPos + 1) + checkSonsLen(n, bodyPos + 1, c.config) var s: PSym if n[namePos].kind != nkSym: s = newSym(skProc, c.cache.idAnon, getCurrOwner(c), n.info) @@ -1228,7 +1228,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = s.options = gOptions if n.sons[bodyPos].kind != nkEmpty: if sfImportc in s.flags: - localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) + localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s) #if efDetermineType notin flags: # XXX not good enough; see tnamedparamanonproc.nim if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags): @@ -1239,10 +1239,10 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = n.sons[bodyPos] = transformBody(c.module, semBody, s) popProcCon(c) elif efOperand notin flags: - localError(n.info, errGenericLambdaNotAllowed) + localError(c.config, n.info, errGenericLambdaNotAllowed) sideEffectsCheck(c, s) else: - localError(n.info, errImplOfXexpected, s.name.s) + localError(c.config, n.info, errImplOfXexpected, s.name.s) closeScope(c) # close scope for parameters popOwner(c) result.typ = s.typ @@ -1267,7 +1267,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = for i in 1..= result.safeLen: return result @@ -1685,8 +1685,8 @@ proc semMethod(c: PContext, n: PNode): PNode = else: disp.ast[resultPos].sym.typ = ret proc semConverterDef(c: PContext, n: PNode): PNode = - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter") - checkSonsLen(n, bodyPos + 1) + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "converter") + checkSonsLen(n, bodyPos + 1, c.config) result = semProcAux(c, n, skConverter, converterPragmas) # macros can transform converters to nothing: if namePos >= result.safeLen: return result @@ -1696,12 +1696,12 @@ proc semConverterDef(c: PContext, n: PNode): PNode = if result.kind != nkConverterDef: return var s = result.sons[namePos].sym var t = s.typ - if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter") - if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter") + if t.sons[0] == nil: localError(c.config, n.info, errXNeedsReturnType, "converter") + if sonsLen(t) != 2: localError(c.config, n.info, errXRequiresOneArgument, "converter") addConverter(c, s) proc semMacroDef(c: PContext, n: PNode): PNode = - checkSonsLen(n, bodyPos + 1) + checkSonsLen(n, bodyPos + 1, c.config) result = semProcAux(c, n, skMacro, macroPragmas) # macros can transform macros to nothing: if namePos >= result.safeLen: return result @@ -1716,18 +1716,18 @@ proc semMacroDef(c: PContext, n: PNode): PNode = let param = t.n.sons[i].sym if param.typ.kind != tyExpr: allUntyped = false if allUntyped: incl(s.flags, sfAllUntyped) - if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro") + if t.sons[0] == nil: localError(c.config, n.info, "macro needs a return type") if n.sons[bodyPos].kind == nkEmpty: - localError(n.info, errImplOfXexpected, s.name.s) + localError(c.config, n.info, errImplOfXexpected, s.name.s) proc evalInclude(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) addSon(result, n) for i in countup(0, sonsLen(n) - 1): - var f = checkModuleName(n.sons[i]) + var f = checkModuleName(c.config, n.sons[i]) if f != InvalidFileIDX: if containsOrIncl(c.includedFiles, f.int): - localError(n.info, errRecursiveDependencyX, f.toFilename) + localError(c.config, n.info, errRecursiveDependencyX % f.toFilename) else: addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache))) excl(c.includedFiles, f.int) @@ -1777,7 +1777,7 @@ proc inferConceptStaticParam(c: PContext, inferred, n: PNode) = var typ = inferred.typ let res = semConstExpr(c, n) if not sameType(res.typ, typ.base): - localError(n.info, + localError(c.config, n.info, "cannot infer the concept parameter '%s', due to a type mismatch. " & "attempt to equate '%s' and '%s'.", [inferred.renderTree, $res.typ, $typ.base]) @@ -1818,7 +1818,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = let verdict = semConstExpr(c, n[i]) if verdict.intVal == 0: - localError(result.info, "concept predicate failed") + localError(c.config, result.info, "concept predicate failed") of tyUnknown: continue else: discard if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]): @@ -1839,7 +1839,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = case n.sons[j].kind of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr, nkBlockStmt, nkState: discard - else: localError(n.sons[j].info, errStmtInvalidAfterReturn) + else: localError(c.config, n.sons[j].info, errStmtInvalidAfterReturn) else: discard if result.len == 1 and diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 454dadec09..352bc5c6b0 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -26,6 +26,9 @@ discard """ a way to achieve lexical scoping at compile time. """ +const + errImplOfXNotAllowed = "implementation of '$1' is not allowed" + type TSymBinding = enum spNone, spGenSym, spInject @@ -60,7 +63,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode = # (s.kind notin routineKinds or s.magic != mNone): # for instance 'nextTry' is both in tables.nim and astalgo.nim ... result = newSymNode(s, n.info) - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) else: # semantic checking requires a type; ``fitNode`` deals with it # appropriately @@ -91,20 +94,20 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode = else: for x in items(sc): toBind.incl(x.sym.id) else: - illFormedAst(a) + illFormedAst(a, c.config) result = newNodeI(nkEmpty, n.info) proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode = for i in 0 ..< n.len: - toMixin.incl(considerQuotedIdent(n.sons[i]).id) + toMixin.incl(considerQuotedIdent(c.config, n.sons[i]).id) result = newNodeI(nkEmpty, n.info) -proc replaceIdentBySym(n: var PNode, s: PNode) = +proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) = case n.kind - of nkPostfix: replaceIdentBySym(n.sons[1], s) - of nkPragmaExpr: replaceIdentBySym(n.sons[0], s) + of nkPostfix: replaceIdentBySym(c, n.sons[1], s) + of nkPragmaExpr: replaceIdentBySym(c, n.sons[0], s) of nkIdent, nkAccQuoted, nkSym: n = s - else: illFormedAst(n) + else: illFormedAst(n, c.config) type TemplCtx = object @@ -129,7 +132,7 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode = result = newSymNode(s, n.info) of nkAccQuoted, nkSym: result = n else: - illFormedAst(n) + illFormedAst(n, c.c.config) result = n proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} = @@ -163,7 +166,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode = result.sons[i] = onlyReplaceParams(c, n.sons[i]) proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym = - result = newSym(kind, considerQuotedIdent(n), c.owner, n.info) + result = newSym(kind, considerQuotedIdent(c.c.config, n), c.owner, n.info) incl(result.flags, sfGenSym) incl(result.flags, sfShadowed) @@ -184,12 +187,12 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = n = onlyReplaceParams(c, n) return else: - illFormedAst(x) + illFormedAst(x, c.c.config) let ident = getIdentNode(c, x) if not isTemplParam(c, ident): c.toInject.incl(x.ident.id) else: - replaceIdentBySym(n, ident) + replaceIdentBySym(c.c, n, ident) else: let ident = getIdentNode(c, n) if not isTemplParam(c, ident): @@ -203,17 +206,17 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = # # We need to ensure that both 'a' produce the same gensym'ed symbol. # So we need only check the *current* scope. - let s = localSearchInScope(c.c, considerQuotedIdent ident) + let s = localSearchInScope(c.c, considerQuotedIdent(c.c.config, ident)) if s != nil and s.owner == c.owner and sfGenSym in s.flags: styleCheckUse(n.info, s) - replaceIdentBySym(n, newSymNode(s, n.info)) + replaceIdentBySym(c.c, n, newSymNode(s, n.info)) else: let local = newGenSym(k, ident, c) addPrelimDecl(c.c, local) styleCheckDef(n.info, local) - replaceIdentBySym(n, newSymNode(local, n.info)) + replaceIdentBySym(c.c, n, newSymNode(local, n.info)) else: - replaceIdentBySym(n, ident) + replaceIdentBySym(c.c, n, ident) proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode = incl(s.flags, sfUsed) @@ -249,7 +252,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode = result = n - checkSonsLen(n, bodyPos + 1) + checkSonsLen(n, bodyPos + 1, c.c.config) # routines default to 'inject': if n.kind notin nkLambdaKinds and symBinding(n.sons[pragmasPos]) == spGenSym: let ident = getIdentNode(c, n.sons[namePos]) @@ -281,8 +284,8 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) = for i in countup(start, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a) - checkMinSonsLen(a, 3) + if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.c.config) + checkMinSonsLen(a, 3, c.c.config) var L = sonsLen(a) when defined(nimsuggest): inc c.c.inTypeContext @@ -354,7 +357,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = n.sons[0] = semTemplBody(c, n.sons[0]) for i in countup(1, sonsLen(n)-1): var a = n.sons[i] - checkMinSonsLen(a, 1) + checkMinSonsLen(a, 1, c.c.config) var L = sonsLen(a) for j in countup(0, L-2): a.sons[j] = semTemplBody(c, a.sons[j]) @@ -371,7 +374,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = closeScope(c) closeScope(c) of nkBlockStmt, nkBlockExpr, nkBlockType: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.c.config) openScope(c) if n.sons[0].kind != nkEmpty: addLocalDecl(c, n.sons[0], skLabel) @@ -384,11 +387,11 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = n.sons[1] = semTemplBody(c, n.sons[1]) closeScope(c) of nkTryStmt: - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.c.config) n.sons[0] = semTemplBodyScope(c, n.sons[0]) for i in countup(1, sonsLen(n)-1): var a = n.sons[i] - checkMinSonsLen(a, 1) + checkMinSonsLen(a, 1, c.c.config) var L = sonsLen(a) openScope(c) for j in countup(0, L-2): @@ -402,15 +405,15 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = of nkVarSection: semTemplSomeDecl(c, n, skVar) of nkLetSection: semTemplSomeDecl(c, n, skLet) of nkFormalParams: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.c.config) n.sons[0] = semTemplBody(c, n.sons[0]) semTemplSomeDecl(c, n, skParam, 1) 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) + if (a.kind != nkConstDef): illFormedAst(a, c.c.config) + checkSonsLen(a, 3, c.c.config) addLocalDecl(c, a.sons[0], skConst) a.sons[1] = semTemplBody(c, a.sons[1]) a.sons[2] = semTemplBody(c, a.sons[2]) @@ -418,14 +421,14 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = 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) + if (a.kind != nkTypeDef): illFormedAst(a, c.c.config) + checkSonsLen(a, 3, c.c.config) addLocalDecl(c, a.sons[0], skType) 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) + if (a.kind != nkTypeDef): illFormedAst(a, c.c.config) + checkSonsLen(a, 3, c.c.config) if a.sons[1].kind != nkEmpty: openScope(c) a.sons[1] = semTemplBody(c, a.sons[1]) @@ -468,7 +471,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = for i in 0 ..< n.len: result.add(n[i]) result = semTemplBodySons(c, result) of nkAsgn, nkFastAsgn: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.c.config) let a = n.sons[0] let b = n.sons[1] @@ -610,9 +613,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = result = n if sfCustomPragma in s.flags: if n.sons[bodyPos].kind != nkEmpty: - localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) + localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s) elif n.sons[bodyPos].kind == nkEmpty: - localError(n.info, errImplOfXexpected, s.name.s) + localError(c.config, n.info, "implementation of '$1' expected" % s.name.s) var proto = searchForProc(c, c.currentScope, s) if proto == nil: addInterfaceOverloadableSymAt(c, c.currentScope, s) @@ -655,7 +658,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = if s != nil and s.owner == c.owner and s.kind == skParam: result = newParam(c, n, s) else: - localError(n.info, errInvalidExpression) + localError(c.c.config, n.info, "invalid expression") result = n proc stupidStmtListExpr(n: PNode): bool = @@ -675,7 +678,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = # we support '(pattern){x}' to bind a subpattern to a parameter 'x'; # '(pattern){|x}' does the same but the matches will be gathered in 'x' if n.len != 2: - localError(n.info, errInvalidExpression) + localError(c.c.config, n.info, "invalid expression") elif n.sons[1].kind == nkIdent: n.sons[0] = semPatternBody(c, n.sons[0]) n.sons[1] = expectParam(c, n.sons[1]) @@ -685,9 +688,9 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = n.sons[0] = semPatternBody(c, n.sons[0]) n.sons[1].sons[1] = expectParam(c, n.sons[1].sons[1]) else: - localError(n.info, errInvalidExpression) + localError(c.c.config, n.info, "invalid expression") else: - localError(n.info, errInvalidExpression) + localError(c.c.config, n.info, "invalid expression") of nkStmtList, nkStmtListExpr: if stupidStmtListExpr(n): result = semPatternBody(c, n.lastSon) @@ -759,5 +762,5 @@ proc semPattern(c: PContext, n: PNode): PNode = if result.len == 1: result = result.sons[0] elif result.len == 0: - localError(n.info, errInvalidExpression) + localError(c.config, n.info, "a pattern cannot be empty") closeScope(c) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 537319d66f..f6d23403e4 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -10,6 +10,33 @@ # this module does the semantic checking of type declarations # included from sem.nim +const + errStringLiteralExpected = "string literal expected" + errIntLiteralExpected = "integer literal expected" + errWrongNumberOfVariables = "wrong number of variables" + errInvalidOrderInEnumX = "invalid order in enum '$1'" + errOrdinalTypeExpected = "ordinal type expected" + errSetTooBig = "set is too large" + errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal" + errInheritanceOnlyWithNonFinalObjects = "inheritance only works with non-final objects" + errXExpectsOneTypeParam = "'$1' expects one type parameter" + errArrayExpectsTwoTypeParams = "array expects two type parameters" + errInvalidVisibilityX = "invalid visibility: '$1'" + errInitHereNotAllowed = "initialization not allowed here" + errXCannotBeAssignedTo = "'$1' cannot be assigned to" + errIteratorNotAllowed = "iterators can only be defined at the module's top level" + errXNeedsReturnType = "$1 needs a return type" + errNoReturnTypeDeclared = "no return type declared" + errTIsNotAConcreteType = "'$1' is not a concrete type" + errTypeExpected = "type expected" + errXOnlyAtModuleScope = "'$1' is only allowed at top level" + errDuplicateCaseLabel = "duplicate case label" + errMacroBodyDependsOnGenericTypes = "the macro body cannot be compiled, " & + "because the parameter '$1' has a generic type" + errIllegalRecursionInTypeX = "illegal recursion in type '$1'" + errNoGenericParamsAllowedForX = "no generic parameters allowed for $1" + errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types" + proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = if prev == nil: result = newTypeS(kind, c) @@ -34,11 +61,11 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = base = nil result = newOrPrevType(tyEnum, prev, c) result.n = newNodeI(nkEnumTy, n.info) - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) if n.sons[0].kind != nkEmpty: base = semTypeNode(c, n.sons[0].sons[0], nil) if base.kind != tyEnum: - localError(n.sons[0].info, errInheritanceOnlyWithEnums) + localError(c.config, n.sons[0].info, "inheritance only works with an enum") counter = lastOrd(base) + 1 rawAddSon(result, base) let isPure = result.sym != nil and sfPure in result.sym.flags @@ -58,9 +85,9 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}: x = getOrdValue(v.sons[0]) # first tuple part is the ordinal else: - localError(strVal.info, errStringLiteralExpected) + localError(c.config, strVal.info, errStringLiteralExpected) else: - localError(v.info, errWrongNumberOfVariables) + localError(c.config, v.info, errWrongNumberOfVariables) of tyString, tyCString: strVal = v x = counter @@ -69,7 +96,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if i != 1: if x != counter: incl(result.flags, tfEnumHasHoles) if x < counter: - localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s) + localError(c.config, n.sons[i].info, errInvalidOrderInEnumX % e.name.s) x = counter e.ast = strVal # might be nil counter = x @@ -78,7 +105,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = of nkIdent, nkAccQuoted: e = newSymS(skEnumField, n.sons[i], c) else: - illFormedAst(n[i]) + illFormedAst(n[i], c.config) e.typ = result e.position = int(counter) if e.position == 0: hasNull = true @@ -87,12 +114,13 @@ 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)) + let conf = c.config styleCheckDef(e) if sfGenSym notin e.flags: if not isPure: addDecl(c, e) else: importPureEnumField(c, e) if isPure and strTableIncl(symbols, e): - wrongRedefinition(e.info, e.name.s) + wrongRedefinition(c, e.info, e.name.s) inc(counter) if not hasNull: incl(result.flags, tfNeedsInit) @@ -104,11 +132,11 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType = if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base) if base.kind != tyGenericParam: if not isOrdinalType(base): - localError(n.info, errOrdinalTypeExpected) + localError(c.config, n.info, errOrdinalTypeExpected) elif lengthOrd(base) > MaxSetElements: - localError(n.info, errSetTooBig) + localError(c.config, n.info, errSetTooBig) else: - localError(n.info, errXExpectsOneTypeParam, "set") + localError(c.config, n.info, errXExpectsOneTypeParam % "set") addSonSkipIntLit(result, errorType(c)) proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, @@ -117,10 +145,10 @@ proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, if sonsLen(n) == 2: var base = semTypeNode(c, n.sons[1], nil) if base.kind == tyVoid: - localError(n.info, errTIsNotAConcreteType, typeToString(base)) + localError(c.config, n.info, errTIsNotAConcreteType % typeToString(base)) addSonSkipIntLit(result, base) else: - localError(n.info, errXExpectsOneTypeParam, kindStr) + localError(c.config, n.info, errXExpectsOneTypeParam % kindStr) addSonSkipIntLit(result, errorType(c)) proc semVarargs(c: PContext, n: PNode, prev: PType): PType = @@ -129,9 +157,9 @@ proc semVarargs(c: PContext, n: PNode, prev: PType): PType = var base = semTypeNode(c, n.sons[1], nil) addSonSkipIntLit(result, base) if sonsLen(n) == 3: - result.n = newIdentNode(considerQuotedIdent(n.sons[2]), n.sons[2].info) + result.n = newIdentNode(considerQuotedIdent(c.config, n.sons[2]), n.sons[2].info) else: - localError(n.info, errXExpectsOneTypeParam, "varargs") + localError(c.config, n.info, errXExpectsOneTypeParam % "varargs") addSonSkipIntLit(result, errorType(c)) proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = @@ -140,7 +168,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = else: let isCall = int ord(n.kind in nkCallKinds+{nkBracketExpr}) let n = if n[0].kind == nkBracket: n[0] else: n - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) var t = semTypeNode(c, n.lastSon, nil) if t.kind == tyTypeDesc and tfUnresolved notin t.flags: t = t.base @@ -155,7 +183,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = let region = semTypeNode(c, ni, nil) if region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin { tyError, tyObject}: - message n[i].info, errGenerated, "region needs to be an object type" + message c.config, n[i].info, errGenerated, "region needs to be an object type" addSonSkipIntLit(result, region) addSonSkipIntLit(result, t) if tfPartial in result.flags: @@ -167,7 +195,7 @@ proc semVarType(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyVar, prev, c) var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc}) if base.kind == tyVar: - localError(n.info, errVarVarTypeNotAllowed) + localError(c.config, n.info, "type 'var var' is not allowed") base = base.sons[0] addSonSkipIntLit(result, base) else: @@ -181,7 +209,7 @@ proc semDistinct(c: PContext, n: PNode, prev: PType): PType = proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = assert isRange(n) - checkSonsLen(n, 3) + checkSonsLen(n, 3, c.config) result = newOrPrevType(tyRange, prev, c) result.n = newNodeI(nkRange, n.info) # always create a 'valid' range type, but overwrite it later @@ -189,7 +217,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = addSonSkipIntLit(result, errorType(c)) if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty): - localError(n.info, errRangeIsEmpty) + localError(c.config, n.info, "range is empty") var range: array[2, PNode] range[0] = semExprWithType(c, n[1], {efDetermineType}) @@ -204,11 +232,11 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = if not hasUnknownTypes: if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})): - localError(n.info, errPureTypeMismatch) + localError(c.config, n.info, "type mismatch") elif not rangeT[0].isOrdinalType: - localError(n.info, errOrdinalTypeExpected) + localError(c.config, n.info, "ordinal type expected") elif enumHasHoles(rangeT[0]): - localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s) + localError(c.config, n.info, "enum '$1' has holes" % typeToString(rangeT[0])) for i in 0..1: if hasGenericArguments(range[i]): @@ -218,7 +246,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = result.n.addSon semConstExpr(c, range[i]) if weakLeValue(result.n[0], result.n[1]) == impNo: - localError(n.info, errRangeIsEmpty) + localError(c.config, n.info, "range is empty") result[0] = rangeT[0] @@ -239,13 +267,13 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType = n.sons[1].floatVal < 0.0: incl(result.flags, tfNeedsInit) else: - if n[1].kind == nkInfix and considerQuotedIdent(n[1][0]).s == "..<": - localError(n[0].info, "range types need to be constructed with '..', '..<' is not supported") + if n[1].kind == nkInfix and considerQuotedIdent(c.config, n[1][0]).s == "..<": + localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported") else: - localError(n.sons[0].info, errRangeExpected) + localError(c.config, n.sons[0].info, "expected range") result = newOrPrevType(tyError, prev, c) else: - localError(n.info, errXExpectsOneTypeParam, "range") + localError(c.config, n.info, errXExpectsOneTypeParam % "range") result = newOrPrevType(tyError, prev, c) proc semArrayIndex(c: PContext, n: PNode): PType = @@ -257,7 +285,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType = result = makeRangeWithStaticExpr(c, e.typ.n) elif e.kind in {nkIntLit..nkUInt64Lit}: if e.intVal < 0: - localError(n[1].info, + localError(c.config, n[1].info, "Array length can't be negative, but was " & $e.intVal) result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ) elif e.kind == nkSym and e.typ.kind == tyStatic: @@ -265,12 +293,12 @@ proc semArrayIndex(c: PContext, n: PNode): PType = return semArrayIndex(c, e.sym.ast) if not isOrdinalType(e.typ.lastSon): let info = if n.safeLen > 1: n[1].info else: n.info - localError(info, errOrdinalTypeExpected) + localError(c.config, info, errOrdinalTypeExpected) result = makeRangeWithStaticExpr(c, e) if c.inGenericContext > 0: result.flags.incl tfUnresolved elif e.kind in nkCallKinds and hasGenericArguments(e): if not isOrdinalType(e.typ): - localError(n[1].info, errOrdinalTypeExpected) + localError(c.config, n[1].info, errOrdinalTypeExpected) # This is an int returning call, depending on an # yet unknown generic param (see tgenericshardcases). # We are going to construct a range type that will be @@ -286,7 +314,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType = x.typ.skipTypes({tyTypeDesc})) else: result = x.typ.skipTypes({tyTypeDesc}) - #localError(n[1].info, errConstExprExpected) + #localError(c.config, n[1].info, errConstExprExpected) proc semArray(c: PContext, n: PNode, prev: PType): PType = var base: PType @@ -299,9 +327,9 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}: discard elif not isOrdinalType(indxB): - localError(n.sons[1].info, errOrdinalTypeExpected) + localError(c.config, n.sons[1].info, errOrdinalTypeExpected) elif enumHasHoles(indxB): - localError(n.sons[1].info, errEnumXHasHoles, + localError(c.config, n.sons[1].info, "enum '$1' has holes" % typeToString(indxB.skipTypes({tyRange}))) base = semTypeNode(c, n.sons[2], nil) # ensure we only construct a tyArray when there was no error (bug #3048): @@ -311,7 +339,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = rawAddSonNoPropagationOfTypeFlags(result, indx) addSonSkipIntLit(result, base) else: - localError(n.info, errArrayExpectsTwoTypeParams) + localError(c.config, n.info, errArrayExpectsTwoTypeParams) result = newOrPrevType(tyError, prev, c) proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = @@ -320,10 +348,10 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = var base = semTypeNode(c, n.sons[1], nil) if base.kind != tyGenericParam: if not isOrdinalType(base): - localError(n.sons[1].info, errOrdinalTypeExpected) + localError(c.config, n.sons[1].info, errOrdinalTypeExpected) addSonSkipIntLit(result, base) else: - localError(n.info, errXExpectsOneTypeParam, "ordinal") + localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal") result = newOrPrevType(tyError, prev, c) proc semTypeIdent(c: PContext, n: PNode): PSym = @@ -334,7 +362,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = if result.isNil: result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if result != nil: - markUsed(n.info, result, c.graph.usageSym) + markUsed(c.config, n.info, result, c.graph.usageSym) styleCheckUse(n.info, result) if result.kind == skParam and result.typ.kind == tyTypeDesc: # This is a typedesc param. is it already bound? @@ -345,7 +373,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = if bound != nil: return bound return result if result.typ.sym == nil: - localError(n.info, errTypeExpected) + localError(c.config, n.info, errTypeExpected) return errorSym(c, n) result = result.typ.sym.copySym result.typ = copyType(result.typ, result.typ.owner, true) @@ -359,7 +387,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = result.typ.flags.excl tfWildcard return else: - localError(n.info, errTypeExpected) + localError(c.config, n.info, errTypeExpected) return errorSym(c, n) if result.kind != skType: @@ -370,7 +398,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = amb = nextOverloadIter(ov, c, n) if amb != nil: result = amb else: - if result.kind != skError: localError(n.info, errTypeExpected) + if result.kind != skError: localError(c.config, n.info, errTypeExpected) return errorSym(c, n) if result.typ.kind != tyGenericParam: # XXX get rid of this hack! @@ -385,12 +413,12 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = n.info = oldInfo n.typ = result.typ else: - localError(n.info, errIdentifierExpected) + localError(c.config, n.info, "identifier expected") result = errorSym(c, n) proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType = if sonsLen(n) == 0: - localError(n.info, errTypeExpected) + localError(c.config, n.info, errTypeExpected) result = newOrPrevType(tyTuple, prev, c) for it in n: addSonSkipIntLit(result, semTypeNode(c, it, nil)) @@ -403,23 +431,23 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = var counter = 0 for i in countup(ord(n.kind == nkBracketExpr), sonsLen(n) - 1): var a = n.sons[i] - if (a.kind != nkIdentDefs): illFormedAst(a) - checkMinSonsLen(a, 3) + if (a.kind != nkIdentDefs): illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var length = sonsLen(a) if a.sons[length - 2].kind != nkEmpty: typ = semTypeNode(c, a.sons[length - 2], nil) else: - localError(a.info, errTypeExpected) + localError(c.config, a.info, errTypeExpected) typ = errorType(c) if a.sons[length - 1].kind != nkEmpty: - localError(a.sons[length - 1].info, errInitHereNotAllowed) + localError(c.config, a.sons[length - 1].info, errInitHereNotAllowed) for j in countup(0, length - 3): var field = newSymG(skField, a.sons[j], c) field.typ = typ field.position = counter inc(counter) if containsOrIncl(check, field.name.id): - localError(a.sons[j].info, errAttemptToRedefine, field.name.s) + localError(c.config, a.sons[j].info, "attempt to redefine: " & field.name.s) else: addSon(result.n, newSymNode(field)) addSonSkipIntLit(result, typ) @@ -434,23 +462,23 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, # for gensym'ed identifiers the identifier may already have been # transformed to a symbol and we need to use that here: result = newSymG(kind, n.sons[1], c) - var v = considerQuotedIdent(n.sons[0]) + var v = considerQuotedIdent(c.config, n.sons[0]) if sfExported in allowed and v.id == ord(wStar): incl(result.flags, sfExported) else: if not (sfExported in allowed): - localError(n.sons[0].info, errXOnlyAtModuleScope, "export") + localError(c.config, n.sons[0].info, errXOnlyAtModuleScope % "export") else: - localError(n.sons[0].info, errInvalidVisibilityX, renderTree(n[0])) + localError(c.config, n.sons[0].info, errInvalidVisibilityX % renderTree(n[0])) else: - illFormedAst(n) + illFormedAst(n, c.config) else: result = newSymG(kind, n, c) proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym = if n.kind == nkPragmaExpr: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) result = semIdentVis(c, kind, n.sons[0], allowed) case kind of skType: @@ -471,10 +499,10 @@ proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) = for j in countup(0, sonsLen(t.sons[i]) - 2): if i == branchIndex and j == currentEx: break if overlap(t.sons[i].sons[j].skipConv, ex): - localError(ex.info, errDuplicateCaseLabel) + localError(c.config, ex.info, errDuplicateCaseLabel) proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode = - checkMinSonsLen(t, 1) + checkMinSonsLen(t, 1, c.config) let ac = semConstExpr(c, a) let bc = semConstExpr(c, b) let at = fitNode(c, t.sons[0].typ, ac, ac.info).skipConvTakeType @@ -483,21 +511,21 @@ proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode result = newNodeI(nkRange, a.info) result.add(at) result.add(bt) - if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty) + if emptyRange(ac, bc): localError(c.config, b.info, "range is empty") else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1 proc semCaseBranchRange(c: PContext, t, b: PNode, covered: var BiggestInt): PNode = - checkSonsLen(b, 3) + checkSonsLen(b, 3, c.config) result = semBranchRange(c, t, b.sons[1], b.sons[2], covered) proc semCaseBranchSetElem(c: PContext, t, b: PNode, covered: var BiggestInt): PNode = if isRange(b): - checkSonsLen(b, 3) + checkSonsLen(b, 3, c.config) result = semBranchRange(c, t, b.sons[1], b.sons[2], covered) elif b.kind == nkRange: - checkSonsLen(b, 2) + checkSonsLen(b, 2, c.config) result = semBranchRange(c, t, b.sons[0], b.sons[1], covered) else: result = fitNode(c, t.sons[0].typ, b, b.info) @@ -520,7 +548,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, delSon(branch, 0) return elif r.kind notin {nkCurly, nkBracket} or len(r) == 0: - checkMinSonsLen(t, 1) + checkMinSonsLen(t, 1, c.config) branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r, r.info)) inc(covered) else: @@ -546,37 +574,37 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, 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) + checkMinSonsLen(n, 2, c.config) semRecordNodeAux(c, n.sons[0], check, pos, a, rectype) if a.sons[0].kind != nkSym: - internalError("semRecordCase: discriminant is no symbol") + internalError(c.config, "semRecordCase: discriminant is no symbol") return incl(a.sons[0].sym.flags, sfDiscriminant) var covered: BiggestInt = 0 var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc}) if not isOrdinalType(typ): - localError(n.info, errSelectorMustBeOrdinal) + localError(c.config, n.info, "selector must be of an ordinal type") elif firstOrd(typ) != 0: - localError(n.info, errGenerated, "low(" & $a.sons[0].sym.name.s & + localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s & ") must be 0 for discriminant") elif lengthOrd(typ) > 0x00007FFF: - localError(n.info, errLenXinvalid, a.sons[0].sym.name.s) + localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s) var chckCovered = true for i in countup(1, sonsLen(n) - 1): var b = copyTree(n.sons[i]) addSon(a, b) case n.sons[i].kind of nkOfBranch: - checkMinSonsLen(b, 2) + checkMinSonsLen(b, 2, c.config) semCaseBranch(c, a, b, i, covered) of nkElse: chckCovered = false - checkSonsLen(b, 1) - else: illFormedAst(n) + checkSonsLen(b, 1, c.config) + else: illFormedAst(n, c.config) delSon(b, sonsLen(b) - 1) semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype) - if chckCovered and (covered != lengthOrd(a.sons[0].typ)): - localError(a.info, errNotAllCasesCovered) + if chckCovered and covered != lengthOrd(a.sons[0].typ): + localError(c.config, a.info, "not all cases are covered") addSon(father, a) proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, @@ -587,22 +615,22 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, var branch: PNode = nil # the branch to take for i in countup(0, sonsLen(n) - 1): var it = n.sons[i] - if it == nil: illFormedAst(n) + if it == nil: illFormedAst(n, c.config) var idx = 1 case it.kind of nkElifBranch: - checkSonsLen(it, 2) + checkSonsLen(it, 2, c.config) if c.inGenericContext == 0: var e = semConstBoolExpr(c, it.sons[0]) - if e.kind != nkIntLit: internalError(e.info, "semRecordNodeAux") + if e.kind != nkIntLit: internalError(c.config, e.info, "semRecordNodeAux") elif e.intVal != 0 and branch == nil: branch = it.sons[1] else: it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0])) of nkElse: - checkSonsLen(it, 1) + checkSonsLen(it, 1, c.config) if branch == nil: branch = it.sons[0] idx = 0 - else: illFormedAst(n) + else: illFormedAst(n, c.config) if c.inGenericContext > 0: # use a new check intset here for each branch: var newCheck: IntSet @@ -626,16 +654,16 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, semRecordNodeAux(c, n.sons[i], check, pos, a, rectype) if a != father: addSon(father, a) of nkIdentDefs: - checkMinSonsLen(n, 3) + checkMinSonsLen(n, 3, c.config) var length = sonsLen(n) var a: PNode if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info) else: a = ast.emptyNode if n.sons[length-1].kind != nkEmpty: - localError(n.sons[length-1].info, errInitHereNotAllowed) + localError(c.config, n.sons[length-1].info, errInitHereNotAllowed) var typ: PType if n.sons[length-2].kind == nkEmpty: - localError(n.info, errTypeExpected) + localError(c.config, n.info, errTypeExpected) typ = errorType(c) else: typ = semTypeNode(c, n.sons[length-2], nil) @@ -654,7 +682,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, f.flags = f.flags + ({sfImportc, sfExportc} * fieldOwner.flags) inc(pos) if containsOrIncl(check, f.name.id): - localError(n.sons[i].info, errAttemptToRedefine, f.name.s) + localError(c.config, n.sons[i].info, "attempt to redefine: " & f.name.s) if a.kind == nkEmpty: addSon(father, newSymNode(f)) else: addSon(a, newSymNode(f)) styleCheckDef(f) @@ -664,29 +692,29 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, # inherited from generic/partial specialized parent second check. # There is no branch validity check here if containsOrIncl(check, n.sym.name.id): - localError(n.info, errAttemptToRedefine, n.sym.name.s) + localError(c.config, n.info, "attempt to redefine: " & n.sym.name.s) addSon(father, n) of nkEmpty: discard - else: illFormedAst(n) + else: illFormedAst(n, c.config) proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int, n: PNode) = case n.kind of nkRecCase: - if (n.sons[0].kind != nkSym): internalError(n.info, "addInheritedFieldsAux") + if (n.sons[0].kind != nkSym): internalError(c.config, n.info, "addInheritedFieldsAux") addInheritedFieldsAux(c, check, pos, n.sons[0]) for i in countup(1, sonsLen(n) - 1): case n.sons[i].kind of nkOfBranch, nkElse: addInheritedFieldsAux(c, check, pos, lastSon(n.sons[i])) - else: internalError(n.info, "addInheritedFieldsAux(record case branch)") + else: internalError(c.config, n.info, "addInheritedFieldsAux(record case branch)") of nkRecList: for i in countup(0, sonsLen(n) - 1): addInheritedFieldsAux(c, check, pos, n.sons[i]) of nkSym: incl(check, n.sym.name.id) inc(pos) - else: internalError(n.info, "addInheritedFieldsAux()") + else: internalError(c.config, n.info, "addInheritedFieldsAux()") proc skipGenericInvocation(t: PType): PType {.inline.} = result = t @@ -709,12 +737,12 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = var pos = 0 var base, realBase: PType = nil # n.sons[0] contains the pragmas (if any). We process these later... - checkSonsLen(n, 3) + checkSonsLen(n, 3, c.config) if n.sons[1].kind != nkEmpty: realBase = semTypeNode(c, n.sons[1].sons[0], nil) base = skipTypesOrNil(realBase, skipPtrs) if base.isNil: - localError(n.info, errIllegalRecursionInTypeX, "object") + localError(c.config, n.info, "cannot inherit from a type that is not an object type") else: var concreteBase = skipGenericInvocation(base) if concreteBase.kind in {tyObject, tyGenericParam, @@ -727,11 +755,11 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = addInheritedFields(c, check, pos, concreteBase) else: if concreteBase.kind != tyError: - localError(n.sons[1].info, "inheritance only works with non-final objects; " & + localError(c.config, n.sons[1].info, "inheritance only works with non-final objects; " & "to enable inheritance write '" & typeToString(realBase) & " of RootObj'") base = nil realBase = nil - if n.kind != nkObjectTy: internalError(n.info, "semObjectNode") + if n.kind != nkObjectTy: internalError(c.config, n.info, "semObjectNode") result = newOrPrevType(tyObject, prev, c) rawAddSon(result, realBase) if result.n.isNil: @@ -769,8 +797,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = addDecl(c, param) else: # within a macro, every param has the type NimNode! - let nn = if getCompilerProc("NimNode") != nil: getSysSym"NimNode" - else: getSysSym"PNimrodNode" + let nn = getSysSym(c.graph, param.info, "NimNode") var a = copySym(param) a.typ = nn.typ addDecl(c, a) @@ -780,7 +807,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = let typedescId = getIdent"typedesc" template shouldHaveMeta(t) = - internalAssert tfHasMeta in t.flags + internalAssert c.config, tfHasMeta in t.flags # result.lastSon.flags.incl tfHasMeta proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, @@ -838,7 +865,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, if tfUnresolved in paramType.flags: return # already lifted let base = paramType.base.maybeLift if base.isMetaType and procKind == skMacro: - localError(info, errMacroBodyDependsOnGenericTypes, paramName) + localError(c.config, info, errMacroBodyDependsOnGenericTypes % paramName) result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base])) result.flags.incl({tfHasStatic, tfUnresolved}) @@ -870,7 +897,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, else: for i in 0 ..< paramType.len: if paramType.sons[i] == paramType: - globalError(info, errIllegalRecursionInTypeX, typeToString(paramType)) + globalError(c.config, info, errIllegalRecursionInTypeX % typeToString(paramType)) var lifted = liftingWalk(paramType.sons[i]) if lifted != nil: paramType.sons[i] = lifted @@ -939,7 +966,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), false)) of tyGenericParam: - markUsed(info, paramType.sym, c.graph.usageSym) + markUsed(c.config, info, paramType.sym, c.graph.usageSym) styleCheckUse(info, paramType.sym) if tfWildcard in paramType.flags: paramType.flags.excl tfWildcard @@ -952,7 +979,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType = if n.kind == nkCurlyExpr: result = semTypeNode(c, n.sons[0], nil) - constraint = semNodeKindConstraints(n) + constraint = semNodeKindConstraints(n, c.config) else: result = semTypeNode(c, n, nil) @@ -971,7 +998,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, # for historical reasons (code grows) this is invoked for parameter # lists too and then 'isType' is false. var cl: IntSet - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) result = newProcType(c, n.info, prev) if genericParams != nil and sonsLen(genericParams) == 0: cl = initIntSet() @@ -985,8 +1012,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, # skip this parameter here. It'll then be re-generated in another LL # pass over this instantiation: if a.kind == nkSym and sfFromGeneric in a.sym.flags: continue - illFormedAst(a) - checkMinSonsLen(a, 3) + illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var typ: PType = nil def: PNode = nil @@ -1009,7 +1036,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if not containsGenericType(typ): def = fitNode(c, typ, def, def.info) if not hasType and not hasDefault: - if isType: localError(a.info, "':' expected") + if isType: localError(c.config, a.info, "':' expected") if kind in {skTemplate, skMacro}: typ = newTypeS(tyExpr, c) elif skipTypes(typ, {tyGenericInst, tyAlias, tySink}).kind == tyVoid: @@ -1020,7 +1047,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, let param = strTableGet(c.signatures, arg.name) if param != nil: typ = param.typ else: - localError(a.info, "typeless parameters are obsolete") + localError(c.config, a.info, "typeless parameters are obsolete") typ = errorType(c) let lifted = liftParamType(c, kind, genericParams, typ, arg.name.s, arg.info) @@ -1031,7 +1058,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, inc(counter) if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def) if containsOrIncl(check, arg.name.id): - localError(a.sons[j].info, errAttemptToRedefine, arg.name.s) + localError(c.config, a.sons[j].info, "attempt to redefine: " & arg.name.s) addSon(result.n, newSymNode(arg)) rawAddSon(result, finalType) addParamOrResult(c, arg, kind) @@ -1085,7 +1112,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, n.sym.typ.flags.excl tfWildcard proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) var length = sonsLen(n) for i in countup(0, length - 2): n.sons[i] = semStmt(c, n.sons[i]) @@ -1098,7 +1125,7 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = proc semBlockType(c: PContext, n: PNode, prev: PType): PType = inc(c.p.nestedBlockCounter) - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) openScope(c) if n.sons[0].kind notin {nkEmpty, nkSym}: addDecl(c, newSymS(skLabel, n.sons[0], c)) @@ -1120,20 +1147,20 @@ proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) = realBase = t.sons[0] base = skipTypesOrNil(realBase, skipPtrs) if base.isNil: - localError(n.info, errIllegalRecursionInTypeX, "object") + localError(c.config, n.info, errIllegalRecursionInTypeX % "object") else: let concreteBase = skipGenericInvocation(base) if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: addInheritedFields(c, check, pos, concreteBase) else: if concreteBase.kind != tyError: - localError(n.info, errInheritanceOnlyWithNonFinalObjects) + localError(c.config, n.info, errInheritanceOnlyWithNonFinalObjects) var newf = newNodeI(nkRecList, n.info) semRecordNodeAux(c, t.n, check, pos, newf, t) proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = if s.typ == nil: - localError(n.info, "cannot instantiate the '$1' $2" % + localError(c.config, n.info, "cannot instantiate the '$1' $2" % [s.name.s, ($s.kind).substr(2).toLowerAscii]) return newOrPrevType(tyError, prev, c) @@ -1146,7 +1173,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = template addToResult(typ) = if typ.isNil: - internalAssert false + internalAssert c.config, false rawAddSon(result, typ) else: addSonSkipIntLit(result, typ) @@ -1158,7 +1185,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = elif t.kind != tyGenericBody: # we likely got code of the form TypeA[TypeB] where TypeA is # not generic. - localError(n.info, errNoGenericParamsAllowedForX, s.name.s) + localError(c.config, n.info, errNoGenericParamsAllowedForX % s.name.s) return newOrPrevType(tyError, prev, c) else: var m = newCandidate(c, t) @@ -1169,7 +1196,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = let err = "cannot instantiate " & typeToString(t) & "\n" & "got: <" & describeArgs(c, n) & ">\n" & "but expected: <" & describeArgs(c, t.n, 0) & ">" - localError(n.info, errGenerated, err) + localError(c.config, n.info, errGenerated, err) return newOrPrevType(tyError, prev, c) var isConcrete = true @@ -1187,7 +1214,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = if isConcrete: if s.ast == nil and s.typ.kind != tyCompositeTypeClass: # XXX: What kind of error is this? is it still relevant? - localError(n.info, errCannotInstantiateX, s.name.s) + localError(c.config, n.info, errCannotInstantiateX % s.name.s) result = newOrPrevType(tyError, prev, c) else: result = instGenericContainer(c, n.info, result, @@ -1197,7 +1224,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = # generic/partial specialized parent let tx = result.skipTypes(abstractPtrs, 50) if tx.isNil: - localError(n.info, "invalid recursion in type '$1'" % typeToString(result[0])) + localError(c.config, n.info, "invalid recursion in type '$1'" % typeToString(result[0])) return errorType(c) if tx != result and tx.kind == tyObject and tx.sons[0] != nil: semObjectTypeForInheritedGenericInst(c, n, tx) @@ -1226,7 +1253,7 @@ proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType = let alias = maybeAliasType(c, result, prev) if alias != nil: result = alias else: - localError(n.info, errTypeExpected, n.renderTree) + localError(c.config, n.info, "expected type, but got: " & n.renderTree) result = errorType(c) proc freshType(res, prev: PType): PType {.inline.} = @@ -1277,7 +1304,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = dummyName = param dummyType = candidateTypeSlot - internalAssert dummyName.kind == nkIdent + internalAssert c.config, dummyName.kind == nkIdent var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar, dummyName.ident, owner, param.info) dummyParam.typ = dummyType @@ -1289,7 +1316,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = proc semProcTypeWithScope(c: PContext, n: PNode, prev: PType, kind: TSymKind): PType = - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) openScope(c) result = semProcTypeNode(c, n.sons[0], nil, prev, kind, isType=true) # start with 'ccClosure', but of course pragmas can overwrite this: @@ -1299,7 +1326,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode, s.typ = result if n.sons[1].kind != nkEmpty and n.sons[1].len > 0: pragma(c, s, n.sons[1], procTypePragmas) - when useEffectSystem: setEffectsForProcType(result, n.sons[1]) + when useEffectSystem: setEffectsForProcType(c.graph, result, n.sons[1]) closeScope(c) proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType = @@ -1320,7 +1347,7 @@ proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym = if n.kind == nkType: result = symFromType(n.typ, n.info) else: - localError(n.info, errTypeExpected) + localError(c.config, n.info, errTypeExpected) result = errorSym(c, n) proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = @@ -1332,7 +1359,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkEmpty: discard of nkTypeOfExpr: # for ``type(countup(1,3))``, see ``tests/ttoseq``. - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) let typExpr = semExprWithType(c, n.sons[0], {efInTypeof}) fixupTypeOf(c, prev, typExpr) result = typExpr.typ @@ -1362,21 +1389,21 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = freshType(result, prev) result.flags.excl(tfNotNil) else: - localError(n.info, errGenerated, "invalid type") + localError(c.config, n.info, errGenerated, "invalid type") elif n[0].kind notin nkIdentKinds: result = semTypeExpr(c, n, prev) else: - let op = considerQuotedIdent(n.sons[0]) + let op = considerQuotedIdent(c.config, n.sons[0]) if op.id in {ord(wAnd), ord(wOr)} or op.s == "|": - checkSonsLen(n, 3) + checkSonsLen(n, 3, c.config) var t1 = semTypeNode(c, n.sons[1], nil) t2 = semTypeNode(c, n.sons[2], nil) if t1 == nil: - localError(n.sons[1].info, errTypeExpected) + localError(c.config, n.sons[1].info, errTypeExpected) result = newOrPrevType(tyError, prev, c) elif t2 == nil: - localError(n.sons[2].info, errTypeExpected) + localError(c.config, n.sons[2].info, errTypeExpected) result = newOrPrevType(tyError, prev, c) else: result = if op.id == ord(wAnd): makeAndType(c, t1, t2) @@ -1390,20 +1417,20 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = freshType(result, prev) result.flags.incl(tfNotNil) if notnil notin c.features: - localError(n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}") + localError(c.config, n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}") else: - localError(n.info, errGenerated, "invalid type") + localError(c.config, n.info, errGenerated, "invalid type") of 2: let negated = semTypeNode(c, n.sons[1], prev) result = makeNotType(c, negated) else: - localError(n.info, errGenerated, "invalid type") + localError(c.config, n.info, errGenerated, "invalid type") elif op.id == ord(wPtr): result = semAnyRef(c, n, tyPtr, prev) elif op.id == ord(wRef): result = semAnyRef(c, n, tyRef, prev) elif op.id == ord(wType): - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) let typExpr = semExprWithType(c, n.sons[1], {efInTypeof}) fixupTypeOf(c, prev, typExpr) result = typExpr.typ @@ -1417,7 +1444,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType result = semTypeNode(c, whenResult, prev) of nkBracketExpr: - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) var head = n.sons[0] var s = if head.kind notin nkCallKinds: semTypeIdent(c, head) else: symFromExpectedTypeNode(c, semExpr(c, head)) @@ -1444,7 +1471,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyVar, prev, c) var base = semTypeNode(c, n.sons[1], nil) if base.kind in {tyVar, tyLent}: - localError(n.info, errVarVarTypeNotAllowed) + localError(c.config, n.info, "type 'var var' is not allowed") base = base.sons[0] addSonSkipIntLit(result, base) of mRef: result = semAnyRef(c, n, tyRef, prev) @@ -1454,13 +1481,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkDotExpr: let typeExpr = semExpr(c, n) if typeExpr.typ.isNil: - localError(n.info, "object constructor needs an object type;" & + localError(c.config, n.info, "object constructor needs an object type;" & " for named arguments use '=' instead of ':'") result = errorType(c) elif typeExpr.typ.kind == tyFromExpr: result = typeExpr.typ elif typeExpr.typ.kind != tyTypeDesc: - localError(n.info, errTypeExpected) + localError(c.config, n.info, errTypeExpected) result = errorType(c) else: result = typeExpr.typ.base @@ -1476,10 +1503,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkIdent, nkAccQuoted: var s = semTypeIdent(c, n) if s.typ == nil: - if s.kind != skError: localError(n.info, errTypeExpected) + if s.kind != skError: localError(c.config, n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) elif s.kind == skParam and s.typ.kind == tyTypeDesc: - internalAssert s.typ.base.kind != tyNone and prev == nil + internalAssert c.config, s.typ.base.kind != tyNone and prev == nil result = s.typ.base elif prev == nil: result = s.typ @@ -1506,10 +1533,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = else: assignType(prev, t) result = prev - markUsed(n.info, n.sym, c.graph.usageSym) + markUsed(c.config, n.info, n.sym, c.graph.usageSym) styleCheckUse(n.info, n.sym) else: - if s.kind != skError: localError(n.info, errTypeExpected) + if s.kind != skError: localError(c.config, n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) of nkObjectTy: result = semObjectNode(c, n, prev) of nkTupleTy: result = semTuple(c, n, prev) @@ -1547,7 +1574,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkStmtListType: result = semStmtListType(c, n, prev) of nkBlockType: result = semBlockType(c, n, prev) else: - localError(n.info, errTypeExpected) + localError(c.config, n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) n.typ = result dec c.inTypeContext @@ -1600,10 +1627,10 @@ proc processMagicType(c: PContext, m: PSym) = of mChar: setMagicType(m, tyChar, 1) of mString: setMagicType(m, tyString, ptrSize) - rawAddSon(m.typ, getSysType(tyChar)) + rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) of mCstring: setMagicType(m, tyCString, ptrSize) - rawAddSon(m.typ, getSysType(tyChar)) + rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) of mPointer: setMagicType(m, tyPointer, ptrSize) of mEmptySet: setMagicType(m, tySet, 1) @@ -1649,8 +1676,8 @@ proc processMagicType(c: PContext, m: PSym) = case m.name.s of "lent": setMagicType(m, tyLent, ptrSize) of "sink": setMagicType(m, tySink, 0) - else: localError(m.info, errTypeExpected) - else: localError(m.info, errTypeExpected) + else: localError(c.config, m.info, errTypeExpected) + else: localError(c.config, m.info, errTypeExpected) proc semGenericConstraints(c: PContext, x: PType): PType = result = newTypeWithSons(c, tyGenericParam, @[x]) @@ -1658,11 +1685,11 @@ proc semGenericConstraints(c: PContext, x: PType): PType = proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = result = copyNode(n) if n.kind != nkGenericParams: - illFormedAst(n) + illFormedAst(n, c.config) return for i in countup(0, sonsLen(n)-1): var a = n.sons[i] - if a.kind != nkIdentDefs: illFormedAst(n) + if a.kind != nkIdentDefs: illFormedAst(n, c.config) let L = a.len var def = a[^1] let constraint = a[^2] @@ -1708,7 +1735,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = if paramName.safeLen == 2: if not nimEnableCovariance or paramName[0].ident.s == "in": if father == nil or sfImportc notin father.sym.flags: - localError(paramName.info, errInOutFlagNotExtern, paramName[0].ident.s) + localError(c.config, paramName.info, errInOutFlagNotExtern % $paramName[0]) covarianceFlag = if paramName[0].ident.s == "in": tfContravariant else: tfCovariant if father != nil: father.flags.incl tfCovariant diff --git a/compiler/vm.nim b/compiler/vm.nim index 84057e6566..5aa1517e4e 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1676,7 +1676,7 @@ proc myProcess(c: PPassContext, n: PNode): PNode = let c = PCtx(c) # don't eval errornous code: if c.oldErrorCount == c.config.errorCounter: - evalStmt(PCtx(c), n) + evalStmt(c, n) result = emptyNode else: result = n From dd35111ff27b5aa0a6c67a7afb3bff9c75f036ec Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 19:45:19 +0200 Subject: [PATCH 189/214] semstmts compiles again --- compiler/configuration.nim | 34 ++----- compiler/semasgn.nim | 52 +++++----- compiler/semexprs.nim | 6 +- compiler/semfields.nim | 23 +++-- compiler/semgnrc.nim | 80 +++++++-------- compiler/semstmts.nim | 195 ++++++++++++++++++++----------------- 6 files changed, 192 insertions(+), 198 deletions(-) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index 4b3cecfcab..86e3cabf2f 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -185,7 +185,6 @@ errIntLiteralExpected: "integer literal expected", errIdentifierExpected: "identifier expected, but found '$1'", errNewlineExpected: "newline expected, but found '$1'", errInvalidModuleName: "invalid module name: '$1'", -errRecursiveDependencyX: "recursive dependency: '$1'", errOnOrOffExpected: "'on' or 'off' expected", errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected", errInvalidPragma: "invalid pragma", @@ -193,11 +192,7 @@ errUnknownPragma: "unknown pragma: '$1'", errAtPopWithoutPush: "'pop' without a 'push' pragma", errEmptyAsm: "empty asm statement", errInvalidIndentation: "invalid indentation", -errExceptionAlreadyHandled: "exception already handled", -errYieldNotAllowedHere: "'yield' only allowed in an iterator", -errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator", -errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions", -errCannotReturnExpr: "current routine cannot return an expression", + errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type", errAttemptToRedefine: , errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma", @@ -261,13 +256,10 @@ errExprMustBeBool: "expression must be of type 'bool'", errConstExprExpected: "constant expression expected", errDuplicateCaseLabel: "duplicate case label", errRangeIsEmpty: "range is empty", -errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string", +, errSelectorMustBeOrdinal: "selector must be of an ordinal type", errOrdXMustNotBeNegative: "ord($1) must not be negative", errLenXinvalid: "len($1) must be less than 32768", -errWrongNumberOfVariables: "wrong number of variables", -errExprCannotBeRaised: "only a 'ref object' can be raised", -errBreakOnlyInLoop: "'break' only allowed in loop construct", errTypeXhasUnknownSize: "type '$1' has unknown size", errConstNeedsConstExpr: "a constant can only be initialized with a constant expression", errConstNeedsValue: "a constant needs a value", @@ -288,11 +280,9 @@ errWrongNumberOfArguments: "wrong number of arguments", errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", errXCannotBePassedToProcVar: , -errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", +, errImplOfXexpected: , -errNoSymbolToBorrowFromFound: "no symbol to borrow from found", -errDiscardValueX: "value of type '$1' has to be discarded", -errInvalidDiscard: "statement returns no value that can be discarded", + errIllegalConvFromXtoY: , errCannotBindXTwice: "cannot bind parameter '$1' twice", errInvalidOrderInArrayConstructor: "invalid order in array constructor", @@ -315,7 +305,6 @@ errNoReturnTypeForX: "no return type allowed for $1", errConvNeedsOneArg: "a type conversion needs exactly one argument", errInvalidPragmaX: , errXNotAllowedHere: "$1 not allowed here", -errInvalidControlFlowX: "invalid control flow: $1", errXisNoType: "invalid type: '$1'", errCircumNeedsPointer: "'[]' needs a pointer or reference type", errInvalidExpression: "invalid expression", @@ -325,7 +314,7 @@ errNamedExprExpected: "named expression expected", errNamedExprNotAllowed: "named expression not allowed here", errNoCommand: "no command given", errInvalidCommandX: "invalid command: '$1'", -errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", +errXNeedsParamObjectType: , errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N", errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N", errInstantiationFrom: "template/generic instantiation from here", @@ -344,7 +333,7 @@ errXisNoValidIndexFile: "'$1' is no valid index file", errCannotRenderX: "cannot render reStructuredText element '$1'", errVarVarTypeNotAllowed: , errInstantiateXExplicitly: "instantiate '$1' explicitly", -errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", +errOnlyACallOpCanBeDelegator: , errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " & "because the parameter '$1' has a generic type", @@ -368,18 +357,9 @@ errUnhandledExceptionX: "unhandled exception: $1", errCyclicTree: "macro returned a cyclic abstract syntax tree", errXisNoMacroOrTemplate: "'$1' is no macro or template", errXhasSideEffects: "'$1' can have side effects", -errIteratorExpected: "iterator within for loop context expected", -errLetNeedsInit: "'let' symbol requires an initialization", -errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread", errWrongSymbolX:, errIllegalCaptureX: "illegal capture '$1'", errXCannotBeClosure: "'$1' cannot have 'closure' calling convention", errXMustBeCompileTime: "'$1' can only be used in compile-time context", -errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1", -errCannotInferReturnType: "cannot infer the return type of the proc", -errCannotInferStaticParam: "cannot infer the value of the static param `$1`", -errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " & - "it is used as an operand to another routine and the types " & - "of the generic paramers can be inferred from the expected signature.", -errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.", +, ]# diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 5c7b91f6df..f0fde195c6 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -33,7 +33,7 @@ proc at(a, i: PNode, elemType: PType): PNode = proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) = for i in 0 ..< t.len: - let lit = lowerings.newIntLit(i) + let lit = lowerings.newIntLit(c.c.graph, x.info, i) liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i])) proc dotField(x: PNode, f: PSym): PNode = @@ -66,15 +66,15 @@ proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) = liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y) caseStmt.add(branch) body.add(caseStmt) - localError(c.info, "cannot lift assignment operator to 'case' object") + localError(c.c.config, c.info, "cannot lift assignment operator to 'case' object") of nkRecList: for t in items(n): liftBodyObj(c, t, body, x, y) else: - illFormedAstLocal(n) + illFormedAstLocal(n, c.c.config) proc genAddr(c: PContext; x: PNode): PNode = if x.kind == nkHiddenDeref: - checkSonsLen(x, 1) + checkSonsLen(x, 1, c.config) result = x.sons[0] else: result = newNodeIT(nkHiddenAddr, x.info, makeVarType(c, x.typ)) @@ -82,7 +82,7 @@ proc genAddr(c: PContext; x: PNode): PNode = proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode = if sfError in op.flags: - localError(x.info, errWrongSymbolX, op.name.s) + localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s) result = newNodeI(nkCall, x.info) result.add newSymNode(op) result.add genAddr(c, x) @@ -124,7 +124,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; op = field if op == nil: op = liftBody(c.c, t, c.kind, c.info) - markUsed(c.info, op, c.c.graph.usageSym) + markUsed(c.c.config, c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newAsgnCall(c.c, op, x, y) result = true @@ -134,7 +134,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = of attachedDestructor: let op = t.destructor if op != nil: - markUsed(c.info, op, c.c.graph.usageSym) + markUsed(c.c.config, c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add destructorCall(c.c, op, x) result = true @@ -145,7 +145,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = of attachedDeepCopy: let op = t.deepCopy if op != nil: - markUsed(c.info, op, c.c.graph.usageSym) + markUsed(c.c.config, c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newDeepCopyCall(op, x, y) result = true @@ -163,37 +163,37 @@ proc addVar(father, v, value: PNode) = proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = var temp = newSym(skTemp, getIdent(lowerings.genPrefix), c.fn, c.info) - temp.typ = getSysType(tyInt) + temp.typ = getSysType(c.c.graph, body.info, tyInt) incl(temp.flags, sfFromGeneric) var v = newNodeI(nkVarSection, c.info) result = newSymNode(temp) - v.addVar(result, lowerings.newIntLit(first)) + v.addVar(result, lowerings.newIntLit(c.c.graph, body.info, first)) body.add v -proc genBuiltin(magic: TMagic; name: string; i: PNode): PNode = +proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = result = newNodeI(nkCall, i.info) - result.add createMagic(name, magic).newSymNode + result.add createMagic(g, name, magic).newSymNode result.add i proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = result = newNodeI(nkWhileStmt, c.info, 2) - let cmp = genBuiltin(mLeI, "<=", i) - cmp.add genHigh(dest) - cmp.typ = getSysType(tyBool) + let cmp = genBuiltin(c.c.graph, mLeI, "<=", i) + cmp.add genHigh(c.c.graph, dest) + cmp.typ = getSysType(c.c.graph, c.info, tyBool) result.sons[0] = cmp result.sons[1] = newNodeI(nkStmtList, c.info) -proc addIncStmt(body, i: PNode) = - let incCall = genBuiltin(mInc, "inc", i) - incCall.add lowerings.newIntLit(1) +proc addIncStmt(c: var TLiftCtx; body, i: PNode) = + let incCall = genBuiltin(c.c.graph, mInc, "inc", i) + incCall.add lowerings.newIntLit(c.c.graph, c.info, 1) body.add incCall proc newSeqCall(c: PContext; x, y: PNode): PNode = # don't call genAddr(c, x) here: - result = genBuiltin(mNewSeq, "newSeq", x) - let lenCall = genBuiltin(mLengthSeq, "len", y) - lenCall.typ = getSysType(tyInt) + result = genBuiltin(c.graph, mNewSeq, "newSeq", x) + let lenCall = genBuiltin(c.graph, mLengthSeq, "len", y) + lenCall.typ = getSysType(c.graph, x.info, tyInt) result.add lenCall proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = @@ -212,7 +212,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = let elemType = t.lastSon liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType), y.at(i, elemType)) - addIncStmt(whileLoop.sons[1], i) + addIncStmt(c, whileLoop.sons[1], i) body.add whileLoop else: defaultOp(c, t, body, x, y) @@ -231,20 +231,20 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = # have to go through some indirection; we delegate this to the codegen: let call = newNodeI(nkCall, c.info, 2) call.typ = t - call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy)) + call.sons[0] = newSymNode(createMagic(c.c.graph, "deepCopy", mDeepCopy)) call.sons[1] = y body.add newAsgnStmt(x, call) of tyVarargs, tyOpenArray: - localError(c.info, errGenerated, "cannot copy openArray") + localError(c.c.config, c.info, "cannot copy openArray") of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt, tyTypeDesc, tyGenericInvocation, tyForward: - internalError(c.info, "assignment requested for type: " & typeToString(t)) + internalError(c.c.config, c.info, "assignment requested for type: " & typeToString(t)) of tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink: liftBodyAux(c, lastSon(t), body, x, y) - of tyUnused, tyOptAsRef: internalError("liftBodyAux") + of tyUnused, tyOptAsRef: internalError(c.c.config, "liftBodyAux") proc newProcType(info: TLineInfo; owner: PSym): PType = result = newType(tyProc, owner) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 001e0ccf22..0ca3fcd4ce 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -215,7 +215,7 @@ proc semConv(c: PContext, n: PNode): PNode = elif op.kind in {nkPar, nkTupleConstr} and targetType.kind == tyTuple: op = fitNode(c, targetType, op, result.info) of convNotNeedeed: - message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) + message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) of convNotLegal: result = fitNode(c, result.typ, result.sons[1], result.info) if result == nil: @@ -1494,7 +1494,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = # nil # # comment # are not expressions: - fixNilType(result) + fixNilType(c, result) else: var a = newNodeI(nkAsgn, n.info, 2) a.sons[0] = newSymNode(c.p.resultSym) @@ -2264,7 +2264,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result.kind = nkCall result = semExpr(c, result, flags) of nkBind: - message(n.info, warnDeprecated, "bind") + message(c.config, n.info, warnDeprecated, "bind") result = semExpr(c, n.sons[0], flags) of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy: if c.matchedConcept != nil and n.len == 1: diff --git a/compiler/semfields.nim b/compiler/semfields.nim index 70efe8c4cc..16d79c5590 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -16,16 +16,17 @@ type tupleIndex: int field: PSym replaceByFieldName: bool + c: PContext proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = case n.kind of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n of nkIdent, nkSym: result = n - let ident = considerQuotedIdent(n) + let ident = considerQuotedIdent(c.c.config, n) var L = sonsLen(forLoop) if c.replaceByFieldName: - if ident.id == considerQuotedIdent(forLoop[0]).id: + if ident.id == considerQuotedIdent(c.c.config, forLoop[0]).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 @@ -33,7 +34,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = return # other fields: for i in ord(c.replaceByFieldName)..L-3: - if ident.id == considerQuotedIdent(forLoop[i]).id: + if ident.id == considerQuotedIdent(c.c.config, forLoop[i]).id: var call = forLoop.sons[L-2] var tupl = call.sons[i+1-ord(c.replaceByFieldName)] if c.field.isNil: @@ -47,7 +48,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = break else: if n.kind == nkContinueStmt: - localError(c.config, n.info, errGenerated, + localError(c.c.config, n.info, "'continue' not supported in a 'fields' loop") result = copyNode(n) newSons(result, sonsLen(n)) @@ -63,6 +64,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = case typ.kind of nkSym: var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid + fc.c = c.c fc.field = typ.sym fc.replaceByFieldName = c.m == mFieldPairs openScope(c.c) @@ -76,7 +78,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = let L = forLoop.len let call = forLoop.sons[L-2] if call.len > 2: - localError(c.config, forLoop.info, errGenerated, + localError(c.c.config, forLoop.info, "parallel 'fields' iterator does not work for 'case' objects") return # iterate over the selector: @@ -99,17 +101,17 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = of nkRecList: for t in items(typ): semForObjectFields(c, t, forLoop, father) else: - illFormedAstLocal(typ) + illFormedAstLocal(typ, c.c.config) proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = # so that 'break' etc. work as expected, we produce # a 'while true: stmt; break' loop ... result = newNodeI(nkWhileStmt, n.info, 2) - var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true") + var trueSymbol = strTableGet(c.graph.systemModule.tab, getIdent"true") if trueSymbol == nil: - localError(c.config, n.info, errSystemNeeds, "true") + localError(c.config, n.info, "system needs: 'true'") trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(c), n.info) - trueSymbol.typ = getSysType(tyBool) + trueSymbol.typ = getSysType(c.graph, n.info, tyBool) result.sons[0] = newSymNode(trueSymbol, n.info) var stmts = newNodeI(nkStmtList, n.info) @@ -129,7 +131,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = for i in 1..call.len-1: var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields) if not sameType(tupleTypeA, tupleTypeB): - typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB) + typeMismatch(c.config, call.sons[i].info, tupleTypeA, tupleTypeB) inc(c.p.nestedLoopCounter) if tupleTypeA.kind == tyTuple: @@ -139,6 +141,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = var fc: TFieldInstCtx fc.tupleType = tupleTypeA fc.tupleIndex = i + fc.c = c fc.replaceByFieldName = m == mFieldPairs var body = instFieldLoopBody(fc, loopBody, n) inc c.inUnrolledContext diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 16da06952a..a620c544dd 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -17,13 +17,13 @@ # included from sem.nim -proc getIdentNode(n: PNode): PNode = +proc getIdentNode(c: PContext; n: PNode): PNode = case n.kind - of nkPostfix: result = getIdentNode(n.sons[1]) - of nkPragmaExpr: result = getIdentNode(n.sons[0]) + of nkPostfix: result = getIdentNode(c, n.sons[1]) + of nkPragmaExpr: result = getIdentNode(c, n.sons[0]) of nkIdent, nkAccQuoted, nkSym: result = n else: - illFormedAst(n) + illFormedAst(n, c.config) result = n type @@ -103,8 +103,8 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode = result = n - let ident = considerQuotedIdent(n) - var s = searchInScopes(c, ident).skipAlias(n) + let ident = considerQuotedIdent(c.config, n) + var s = searchInScopes(c, ident).skipAlias(n, c.config) if s == nil: s = strTableGet(c.pureEnumFields, ident) if s != nil and contains(c.ambiguousSymbols, s.id): @@ -140,8 +140,8 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx) result = n let n = n[1] - let ident = considerQuotedIdent(n) - var s = searchInScopes(c, ident).skipAlias(n) + let ident = considerQuotedIdent(c.config, n) + var s = searchInScopes(c, ident).skipAlias(n, c.config) if s != nil and s.kind in routineKinds: isMacro = s.kind in {skTemplate, skMacro} if withinBind in flags: @@ -158,7 +158,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, result = newDot(result, syms) proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = - let s = newSymS(skUnknown, getIdentNode(n), c) + let s = newSymS(skUnknown, getIdentNode(c, n), c) addPrelimDecl(c, s) styleCheckDef(n.info, s, kind) @@ -201,13 +201,13 @@ proc semGenericStmt(c: PContext, n: PNode, result = semMixinStmt(c, n, ctx.toMixin) of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: # check if it is an expression macro: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) let fn = n.sons[0] var s = qualifiedLookUp(c, fn, {}) if s == nil and {withinMixin, withinConcept}*flags == {} and fn.kind in {nkIdent, nkAccQuoted} and - considerQuotedIdent(fn).id notin ctx.toMixin: + considerQuotedIdent(c.config, fn).id notin ctx.toMixin: errorUndeclaredIdentifier(c, n.info, fn.renderTree) var first = int ord(withinConcept in flags) @@ -285,7 +285,7 @@ proc semGenericStmt(c: PContext, n: PNode, withBracketExpr ctx, n.sons[0]: result = semGenericStmt(c, result, flags, ctx) of nkAsgn, nkFastAsgn: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) let a = n.sons[0] let b = n.sons[1] @@ -323,7 +323,7 @@ proc semGenericStmt(c: PContext, n: PNode, n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx) for i in countup(1, sonsLen(n)-1): var a = n.sons[i] - checkMinSonsLen(a, 1) + checkMinSonsLen(a, 1, c.config) var L = sonsLen(a) for j in countup(0, L-2): a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx) @@ -340,23 +340,23 @@ proc semGenericStmt(c: PContext, n: PNode, closeScope(c) closeScope(c) of nkBlockStmt, nkBlockExpr, nkBlockType: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) openScope(c) if n.sons[0].kind != nkEmpty: addTempDecl(c, n.sons[0], skLabel) n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) closeScope(c) of nkTryStmt: - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx) for i in countup(1, sonsLen(n)-1): var a = n.sons[i] - checkMinSonsLen(a, 1) + checkMinSonsLen(a, 1, c.config) var L = sonsLen(a) openScope(c) for j in countup(0, L-2): if a.sons[j].isInfixAs(): - addTempDecl(c, getIdentNode(a.sons[j][2]), skLet) + addTempDecl(c, getIdentNode(c, a.sons[j][2]), skLet) a.sons[j].sons[1] = semGenericStmt(c, a.sons[j][1], flags+{withinTypeDesc}, ctx) else: a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx) @@ -367,44 +367,44 @@ proc semGenericStmt(c: PContext, n: PNode, for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a) - checkMinSonsLen(a, 3) + if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var L = sonsLen(a) 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): - addTempDecl(c, getIdentNode(a.sons[j]), skVar) + addTempDecl(c, getIdentNode(c, a.sons[j]), skVar) of nkGenericParams: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if (a.kind != nkIdentDefs): illFormedAst(a) - checkMinSonsLen(a, 3) + if (a.kind != nkIdentDefs): illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var L = sonsLen(a) 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): - addTempDecl(c, getIdentNode(a.sons[j]), skType) + addTempDecl(c, getIdentNode(c, 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) - addTempDecl(c, getIdentNode(a.sons[0]), skConst) + if (a.kind != nkConstDef): illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) + addTempDecl(c, getIdentNode(c, 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: 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) - addTempDecl(c, getIdentNode(a.sons[0]), skType) + if (a.kind != nkTypeDef): illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) + addTempDecl(c, getIdentNode(c, a.sons[0]), skType) 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) + if (a.kind != nkTypeDef): illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) if a.sons[1].kind != nkEmpty: openScope(c) a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx) @@ -421,28 +421,28 @@ proc semGenericStmt(c: PContext, n: PNode, case n.sons[i].kind of nkEnumFieldDef: a = n.sons[i].sons[0] of nkIdent: a = n.sons[i] - else: illFormedAst(n) - addDecl(c, newSymS(skUnknown, getIdentNode(a), c)) + else: illFormedAst(n, c.config) + addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c)) of nkObjectTy, nkTupleTy, nkTupleClassTy: discard of nkFormalParams: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) if n.sons[0].kind != nkEmpty: n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx) for i in countup(1, sonsLen(n) - 1): var a = n.sons[i] - if (a.kind != nkIdentDefs): illFormedAst(a) - checkMinSonsLen(a, 3) + if (a.kind != nkIdentDefs): illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var L = sonsLen(a) 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): - addTempDecl(c, getIdentNode(a.sons[j]), skParam) + addTempDecl(c, getIdentNode(c, a.sons[j]), skParam) of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkFuncDef, nkIteratorDef, nkLambdaKinds: - checkSonsLen(n, bodyPos + 1) + checkSonsLen(n, bodyPos + 1, c.config) if n.sons[namePos].kind != nkEmpty: - addTempDecl(c, getIdentNode(n.sons[0]), skProc) + addTempDecl(c, getIdentNode(c, n.sons[0]), skProc) openScope(c) n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], flags, ctx) @@ -463,7 +463,7 @@ proc semGenericStmt(c: PContext, n: PNode, closeScope(c) of nkPragma, nkPragmaExpr: discard of nkExprColonExpr, nkExprEqExpr: - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) else: for i in countup(0, sonsLen(n) - 1): diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f1a34785b7..f09fad5885 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -10,7 +10,33 @@ ## this module does the semantic checking of statements # included from sem.nim -var enforceVoidContext = PType(kind: tyStmt) +const + errNoSymbolToBorrowFromFound = "no symbol to borrow from found" + errDiscardValueX = "value of type '$1' has to be discarded" + errInvalidDiscard = "statement returns no value that can be discarded" + errInvalidControlFlowX = "invalid control flow: $1" + errSelectorMustBeOfCertainTypes = "selector must be of an ordinal type, float or string" + errExprCannotBeRaised = "only a 'ref object' can be raised" + errBreakOnlyInLoop = "'break' only allowed in loop construct" + errExceptionAlreadyHandled = "exception already handled" + errYieldNotAllowedHere = "'yield' only allowed in an iterator" + errYieldNotAllowedInTryStmt = "'yield' cannot be used within 'try' in a non-inlined iterator" + errInvalidNumberOfYieldExpr = "invalid number of 'yield' expressions" + errCannotReturnExpr = "current routine cannot return an expression" + errGenericLambdaNotAllowed = "A nested proc can have generic parameters only when " & + "it is used as an operand to another routine and the types " & + "of the generic paramers can be inferred from the expected signature." + errCannotInferTypeOfTheLiteral = "cannot infer the type of the $1" + errCannotInferReturnType = "cannot infer the return type of the proc" + errCannotInferStaticParam = "cannot infer the value of the static param '$1'" + errProcHasNoConcreteType = "'$1' doesn't have a concrete type, due to unspecified generic parameters." + errLetNeedsInit = "'let' symbol requires an initialization" + errThreadvarCannotInit = "a thread var cannot be initialized explicitly; this would only run for the main thread" + errImplOfXexpected = "implementation of '$1' expected" + errRecursiveDependencyX = "recursive dependency: '$1'" + errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1" + +var enforceVoidContext = PType(kind: tyStmt) # XXX global variable here proc semDiscard(c: PContext, n: PNode): PNode = result = n @@ -39,18 +65,18 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = suggestSym(x.info, s, c.graph.usageSym) styleCheckUse(x.info, s) else: - localError(c.config, n.info, errInvalidControlFlowX, s.name.s) + localError(c.config, n.info, errInvalidControlFlowX % s.name.s) else: localError(c.config, n.info, errGenerated, "'continue' cannot have a label") elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): - localError(c.config, n.info, errInvalidControlFlowX, + localError(c.config, n.info, errInvalidControlFlowX % renderTree(n, {renderNoComments})) -proc semAsm(con: PContext, n: PNode): PNode = +proc semAsm(c: PContext, n: PNode): PNode = checkSonsLen(n, 2, c.config) - var marker = pragmaAsm(con, n.sons[0]) + var marker = pragmaAsm(c, n.sons[0]) if marker == '\0': marker = '`' # default marker - result = semAsmOrEmit(con, n, marker) + result = semAsmOrEmit(c, n, marker) proc semWhile(c: PContext, n: PNode): PNode = result = n @@ -95,13 +121,13 @@ proc implicitlyDiscardable(n: PNode): bool = result = isCallExpr(n) and n.sons[0].kind == nkSym and sfDiscardable in n.sons[0].sym.flags -proc fixNilType(n: PNode) = +proc fixNilType(c: PContext; n: PNode) = if isAtom(n): if n.kind != nkNilLit and n.typ != nil: - localError(c.config, n.info, errDiscardValueX, n.typ.typeToString) + localError(c.config, n.info, errDiscardValueX % n.typ.typeToString) elif n.kind in {nkStmtList, nkStmtListExpr}: n.kind = nkStmtList - for it in n: fixNilType(it) + for it in n: fixNilType(c, it) n.typ = nil proc discardCheck(c: PContext, result: PNode) = @@ -207,7 +233,7 @@ proc semCase(c: PContext, n: PNode): PNode = if covered == toCover(n.sons[0].typ): hasElse = true else: - localError(c.config, n.info, errNotAllCasesCovered) + localError(c.config, n.info, "not all cases covered") closeScope(c) if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) @@ -339,16 +365,16 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = result = semIdentWithPragma(c, kind, n, {}) if result.owner.kind == skModule: incl(result.flags, sfGlobal) - suggestSym(c.config, n.info, result, c.graph.usageSym) + suggestSym(n.info, result, c.graph.usageSym) styleCheckDef(result) -proc checkNilable(v: PSym) = +proc checkNilable(c: PContext; v: PSym) = if {sfGlobal, sfImportC} * v.flags == {sfGlobal} and {tfNotNil, tfNeedsInit} * v.typ.flags != {}: if v.ast.isNil: - message(v.info, warnProveInit, v.name.s) + message(c.config, v.info, warnProveInit, v.name.s) elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags: - message(v.info, warnProveInit, v.name.s) + message(c.config, v.info, warnProveInit, v.name.s) include semasgn @@ -369,7 +395,7 @@ proc isDiscardUnderscore(v: PSym): bool = proc semUsing(c: PContext; n: PNode): PNode = result = ast.emptyNode - if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "using") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "using") for i in countup(0, sonsLen(n)-1): var a = n.sons[i] if gCmd == cmdIdeTools: suggestStmt(c, a) @@ -432,7 +458,7 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) = else: localError(c.config, n.info, "nkDotNode requires 2 children") -proc setVarType(v: PSym, typ: PType) = +proc setVarType(c: PContext; v: PSym, typ: PType) = if v.typ != nil and not sameTypeOrNil(v.typ, typ): localError(c.config, v.info, "inconsistent typing for reintroduced symbol '" & v.name.s & "': previous type was: " & typeToString(v.typ) & @@ -476,16 +502,16 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass: typ = typ.lastSon if hasEmpty(typ): - localError(c.config, def.info, errCannotInferTypeOfTheLiteral, + localError(c.config, def.info, errCannotInferTypeOfTheLiteral % ($typ.kind).substr(2).toLowerAscii) elif typ.kind == tyProc and tfUnresolved in typ.flags: - localError(c.config, def.info, errProcHasNoConcreteType, def.renderTree) + localError(c.config, def.info, errProcHasNoConcreteType % def.renderTree) else: if symkind == skLet: localError(c.config, a.info, errLetNeedsInit) # this can only happen for errornous var statements: if typ == nil: continue - typeAllowedCheck(a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {}) + typeAllowedCheck(c.config, a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {}) liftTypeBoundOps(c, typ, a.info) var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink}) if a.kind == nkVarTuple: @@ -500,7 +526,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = addToVarSection(c, result, n, b) elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and a.kind == nkIdentDefs and a.len > 3: - message(a.info, warnEachIdentIsTuple) + message(c.config, a.info, warnEachIdentIsTuple) for j in countup(0, length-3): if a[j].kind == nkDotExpr: @@ -518,17 +544,17 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if shadowed != nil: shadowed.flags.incl(sfShadowed) if shadowed.kind == skResult and sfGenSym notin v.flags: - message(a.info, warnResultShadowed) + message(c.config, a.info, warnResultShadowed) # a shadowed variable is an error unless it appears on the right # side of the '=': - if warnShadowIdent in gNotes and not identWithin(def, v.name): - message(a.info, warnShadowIdent, v.name.s) + if warnShadowIdent in c.config.notes and not identWithin(def, v.name): + message(c.config, a.info, warnShadowIdent, v.name.s) if a.kind != nkVarTuple: if def.kind != nkEmpty: # this is needed for the evaluation pass and for the guard checking: v.ast = def if sfThread in v.flags: localError(c.config, def.info, errThreadvarCannotInit) - setVarType(v, typ) + setVarType(c, v, typ) b = newNodeI(nkIdentDefs, a.info) if importantComments(c.config): # keep documentation information: @@ -540,13 +566,13 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = else: if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j] # bug #7663, for 'nim check' this can be a non-tuple: - if tup.kind == tyTuple: setVarType(v, tup.sons[j]) + if tup.kind == tyTuple: setVarType(c, v, tup.sons[j]) else: v.typ = tup b.sons[j] = newSymNode(v) - checkNilable(v) + checkNilable(c, v) if sfCompileTime in v.flags: hasCompileTime = true if hasCompileTime: - vm.setupCompileTimeVar(c.module, c.cache, c.graph.config, result) + vm.setupCompileTimeVar(c.module, c.cache, c.graph, result) proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) @@ -575,11 +601,11 @@ proc semConst(c: PContext, n: PNode): PNode = if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit: localError(c.config, a.info, "invalid type for const: " & typeToString(typ)) continue - setVarType(v, typ) + setVarType(c, v, typ) v.ast = def # no need to copy if sfGenSym notin v.flags: addInterfaceDecl(c, v) var b = newNodeI(nkConstDef, a.info) - if importantComments(): b.comment = a.comment + if importantComments(c.config): b.comment = a.comment addSon(b, newSymNode(v)) addSon(b, a.sons[1]) addSon(b, copyTree(def)) @@ -588,12 +614,12 @@ proc semConst(c: PContext, n: PNode): PNode = include semfields proc addForVarDecl(c: PContext, v: PSym) = - if warnShadowIdent in gNotes: + if warnShadowIdent in c.config.notes: let shadowed = findShadowedVar(c, v) if shadowed != nil: # XXX should we do this here? #shadowed.flags.incl(sfShadowed) - message(v.info, warnShadowIdent, v.name.s) + message(c.config, v.info, warnShadowIdent, v.name.s) addDecl(c, v) proc symForVar(c: PContext, n: PNode): PSym = @@ -658,7 +684,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode = # n := for a, b, c in m(x, y, z): Y # to # m(n) - let forLoopStmt = magicsys.getCompilerProc("ForLoopStmt") + let forLoopStmt = magicsys.getCompilerProc(c.graph, "ForLoopStmt") if forLoopStmt == nil: return let headSymbol = iterExpr[0] @@ -715,7 +741,7 @@ proc semFor(c: PContext, n: PNode): PNode = elif length == 4: n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2]) else: - localError(c.config, n.sons[length-2].info, errIteratorExpected) + localError(c.config, n.sons[length-2].info, "iterator within for loop context expected") result = semForVars(c, n) else: result = semForVars(c, n) @@ -744,7 +770,7 @@ proc addGenericParamListToScope(c: PContext, n: PNode) = if a.kind == nkSym: addDecl(c, a.sym) else: illFormedAst(a, c.config) -proc typeSectionTypeName(n: PNode): PNode = +proc typeSectionTypeName(c: PContext; n: PNode): PNode = if n.kind == nkPragmaExpr: if n.len == 0: illFormedAst(n, c.config) result = n.sons[0] @@ -818,14 +844,12 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = else: a.sons[0] = newSymNode(s) -proc checkCovariantParamsUsages(genericType: PType) = +proc checkCovariantParamsUsages(c: PContext; genericType: PType) = var body = genericType[^1] - proc traverseSubTypes(t: PType): bool = + proc traverseSubTypes(c: PContext; t: PType): bool = template error(msg) = localError(c.config, genericType.sym.info, msg) - result = false - template subresult(r) = let sub = r result = result or sub @@ -834,24 +858,19 @@ proc checkCovariantParamsUsages(genericType: PType) = of tyGenericParam: t.flags.incl tfWeakCovariant return true - of tyObject: for field in t.n: - subresult traverseSubTypes(field.typ) - + subresult traverseSubTypes(c, field.typ) of tyArray: - return traverseSubTypes(t[1]) - + return traverseSubTypes(c, t[1]) of tyProc: for subType in t.sons: if subType != nil: - subresult traverseSubTypes(subType) + subresult traverseSubTypes(c, subType) if result: error("non-invariant type param used in a proc type: " & $t) - of tySequence: - return traverseSubTypes(t[0]) - + return traverseSubTypes(c, t[0]) of tyGenericInvocation: let targetBody = t[0] for i in 1 ..< t.len: @@ -872,32 +891,24 @@ proc checkCovariantParamsUsages(genericType: PType) = "' used in a non-contravariant position") result = true else: - subresult traverseSubTypes(param) - + subresult traverseSubTypes(c, param) of tyAnd, tyOr, tyNot, tyStatic, tyBuiltInTypeClass, tyCompositeTypeClass: error("non-invariant type parameters cannot be used with types such '" & $t & "'") - of tyUserTypeClass, tyUserTypeClassInst: error("non-invariant type parameters are not supported in concepts") - of tyTuple: for fieldType in t.sons: - subresult traverseSubTypes(fieldType) - + subresult traverseSubTypes(c, fieldType) of tyPtr, tyRef, tyVar, tyLent: if t.base.kind == tyGenericParam: return true - return traverseSubTypes(t.base) - + return traverseSubTypes(c, t.base) of tyDistinct, tyAlias, tySink: - return traverseSubTypes(t.lastSon) - + return traverseSubTypes(c, t.lastSon) of tyGenericInst: - internalAssert false - + internalAssert c.config, false else: discard - - discard traverseSubTypes(body) + discard traverseSubTypes(c, body) proc typeSectionRightSidePass(c: PContext, n: PNode) = for i in countup(0, sonsLen(n) - 1): @@ -905,10 +916,10 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = if a.kind == nkCommentStmt: continue if a.kind != nkTypeDef: illFormedAst(a, c.config) checkSonsLen(a, 3, c.config) - let name = typeSectionTypeName(a.sons[0]) + let name = typeSectionTypeName(c, a.sons[0]) var s = name.sym if s.magic == mNone and a.sons[2].kind == nkEmpty: - localError(c.config, a.info, errImplOfXexpected, s.name.s) + localError(c.config, a.info, errImplOfXexpected % s.name.s) if s.magic != mNone: processMagicType(c, s) if a.sons[1].kind != nkEmpty: # We have a generic type declaration here. In generic types, @@ -939,7 +950,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = body.size = -1 # could not be computed properly s.typ.sons[sonsLen(s.typ) - 1] = body if tfCovariant in s.typ.flags: - checkCovariantParamsUsages(s.typ) + checkCovariantParamsUsages(c, s.typ) # XXX: This is a temporary limitation: # The codegen currently produces various failures with # generic imported types that have fields, but we need @@ -974,8 +985,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # give anonymous object a dummy symbol: var st = s.typ if st.kind == tyGenericBody: st = st.lastSon - internalAssert st.kind in {tyPtr, tyRef} - internalAssert st.lastSon.sym == nil + internalAssert c.config, st.kind in {tyPtr, tyRef} + internalAssert c.config, st.lastSon.sym == nil incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(s.name.s & ":ObjectType"), getCurrOwner(c), s.info) @@ -983,17 +994,17 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = st.lastSon.sym = obj -proc checkForMetaFields(n: PNode) = +proc checkForMetaFields(c: PContext; n: PNode) = template checkMeta(t) = if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags: - localError(c.config, n.info, errTIsNotAConcreteType, t.typeToString) + localError(c.config, n.info, errTIsNotAConcreteType % t.typeToString) if n.isNil: return case n.kind of nkRecList, nkRecCase: - for s in n: checkForMetaFields(s) + for s in n: checkForMetaFields(c, s) of nkOfBranch, nkElse: - checkForMetaFields(n.lastSon) + checkForMetaFields(c, n.lastSon) of nkSym: let t = n.sym.typ case t.kind @@ -1005,13 +1016,13 @@ proc checkForMetaFields(n: PNode) = else: checkMeta(t) else: - internalAssert false + internalAssert c.config, false proc typeSectionFinalPass(c: PContext, n: PNode) = for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - let name = typeSectionTypeName(a.sons[0]) + let name = typeSectionTypeName(c, a.sons[0]) var s = name.sym # compute the type's size and check for illegal recursions: if a.sons[1].kind == nkEmpty: @@ -1031,9 +1042,9 @@ proc typeSectionFinalPass(c: PContext, n: PNode) = assert s.typ != nil assignType(s.typ, t) s.typ.id = t.id # same id - checkConstructedType(s.info, s.typ) + checkConstructedType(c.config, s.info, s.typ) if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil: - checkForMetaFields(s.typ.n) + checkForMetaFields(c, s.typ.n) instAllTypeBoundOp(c, n.info) @@ -1042,10 +1053,10 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode = case n.kind of nkIncludeStmt: for i in 0..= result.safeLen: return result @@ -1685,7 +1696,7 @@ proc semMethod(c: PContext, n: PNode): PNode = else: disp.ast[resultPos].sym.typ = ret proc semConverterDef(c: PContext, n: PNode): PNode = - if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "converter") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "converter") checkSonsLen(n, bodyPos + 1, c.config) result = semProcAux(c, n, skConverter, converterPragmas) # macros can transform converters to nothing: @@ -1696,8 +1707,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode = if result.kind != nkConverterDef: return var s = result.sons[namePos].sym var t = s.typ - if t.sons[0] == nil: localError(c.config, n.info, errXNeedsReturnType, "converter") - if sonsLen(t) != 2: localError(c.config, n.info, errXRequiresOneArgument, "converter") + if t.sons[0] == nil: localError(c.config, n.info, errXNeedsReturnType % "converter") + if sonsLen(t) != 2: localError(c.config, n.info, "a converter takes exactly one argument") addConverter(c, s) proc semMacroDef(c: PContext, n: PNode): PNode = @@ -1718,7 +1729,7 @@ proc semMacroDef(c: PContext, n: PNode): PNode = if allUntyped: incl(s.flags, sfAllUntyped) if t.sons[0] == nil: localError(c.config, n.info, "macro needs a return type") if n.sons[bodyPos].kind == nkEmpty: - localError(c.config, n.info, errImplOfXexpected, s.name.s) + localError(c.config, n.info, errImplOfXexpected % s.name.s) proc evalInclude(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) @@ -1756,7 +1767,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode = #writeStackTrace() let a = semStmt(c, n.sons[0]) n.sons[0] = a - evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner) + evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner) result = newNodeI(nkDiscardStmt, n.info, 1) result.sons[0] = emptyNode @@ -1839,7 +1850,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = case n.sons[j].kind of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr, nkBlockStmt, nkState: discard - else: localError(c.config, n.sons[j].info, errStmtInvalidAfterReturn) + else: localError(c.config, n.sons[j].info, "unreachable statement after 'return'") else: discard if result.len == 1 and From 050789a8f4c3649adbd588f96023d63a9aabce45 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 21:30:42 +0200 Subject: [PATCH 190/214] sem pass compiles again --- compiler/ccgliterals.nim | 2 +- compiler/ccgmerge.nim | 34 ++--- compiler/cgen.nim | 10 +- compiler/cgendata.nim | 3 + compiler/configuration.nim | 18 +-- compiler/magicsys.nim | 9 +- compiler/modulegraphs.nim | 9 +- compiler/sem.nim | 44 +++--- compiler/semexprs.nim | 295 +++++++++++++++++++------------------ compiler/semmagic.nim | 42 +++--- compiler/semobjconstr.nim | 62 ++++---- compiler/semstmts.nim | 4 +- 12 files changed, 269 insertions(+), 263 deletions(-) diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim index b17a5eeddf..0bd00a6968 100644 --- a/compiler/ccgliterals.nim +++ b/compiler/ccgliterals.nim @@ -15,7 +15,7 @@ template detectVersion(field, corename) = if m.g.field == 0: - let core = getCompilerProc(corename) + let core = getCompilerProc(m.g. corename) if core == nil or core.kind != skConst: m.g.field = 1 else: diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index f667be70f2..4b4f9c0e68 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -45,28 +45,28 @@ const ] NimMergeEndMark = "/*\tNIM_merge_END:*/" -proc genSectionStart*(fs: TCFileSection): Rope = - if compilationCachePresent: +proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): result = rope(tnl) add(result, "/*\t") add(result, CFileSectionNames[fs]) add(result, ":*/") add(result, tnl) -proc genSectionEnd*(fs: TCFileSection): Rope = - if compilationCachePresent: +proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): result = rope(NimMergeEndMark & tnl) -proc genSectionStart*(ps: TCProcSection): Rope = - if compilationCachePresent: +proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): result = rope(tnl) add(result, "/*\t") add(result, CProcSectionNames[ps]) add(result, ":*/") add(result, tnl) -proc genSectionEnd*(ps: TCProcSection): Rope = - if compilationCachePresent: +proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): result = rope(NimMergeEndMark & tnl) proc writeTypeCache(a: TypeCache, s: var string) = @@ -96,7 +96,7 @@ proc writeIntSet(a: IntSet, s: var string) = s.add('}') proc genMergeInfo*(m: BModule): Rope = - if not compilationCachePresent: return nil + if not compilationCachePresent(m.config): return nil var s = "/*\tNIM_merge_INFO:" s.add(tnl) s.add("typeCache:{") @@ -161,7 +161,7 @@ proc readVerbatimSection(L: var TBaseLexer): Rope = buf = L.buf r.add(tnl) of '\0': - internalError("ccgmerge: expected: " & NimMergeEndMark) + doAssert(false, "ccgmerge: expected: " & NimMergeEndMark) break else: if atEndMark(buf, pos): @@ -179,7 +179,7 @@ proc readKey(L: var TBaseLexer, result: var string) = while buf[pos] in IdentChars: result.add(buf[pos]) inc pos - if buf[pos] != ':': internalError("ccgmerge: ':' expected") + if buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected") L.bufpos = pos + 1 # skip ':' proc newFakeType(id: int): PType = @@ -187,12 +187,12 @@ proc newFakeType(id: int): PType = result.id = id proc readTypeCache(L: var TBaseLexer, result: var TypeCache) = - if ^L.bufpos != '{': internalError("ccgmerge: '{' expected") + if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") inc L.bufpos while ^L.bufpos != '}': skipWhite(L) var key = decodeStr(L.buf, L.bufpos) - if ^L.bufpos != ':': internalError("ccgmerge: ':' expected") + if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected") inc L.bufpos var value = decodeStr(L.buf, L.bufpos) # XXX implement me @@ -201,7 +201,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TypeCache) = inc L.bufpos proc readIntSet(L: var TBaseLexer, result: var IntSet) = - if ^L.bufpos != '{': internalError("ccgmerge: '{' expected") + if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") inc L.bufpos while ^L.bufpos != '}': skipWhite(L) @@ -225,7 +225,7 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) = of "labels": m.labels = decodeVInt(L.buf, L.bufpos) of "flags": m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0) - else: internalError("ccgmerge: unknown key: " & k) + else: doAssert(false, "ccgmerge: unknown key: " & k) when not defined(nimhygiene): {.pragma: inject.} @@ -275,9 +275,9 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) = if sectionB >= 0 and sectionB <= high(TCProcSection).int: m.p[TCProcSection(sectionB)] = verbatim else: - internalError("ccgmerge: unknown section: " & k) + doAssert(false, "ccgmerge: unknown section: " & k) else: - internalError("ccgmerge: '*/' expected") + doAssert(false, "ccgmerge: '*/' expected") proc mergeRequired*(m: BModule): bool = for i in cfsHeaders..cfsProcs: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 693930fbc4..78f6099ec7 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -115,7 +115,7 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope = if i >= length or not (frmt[i] in {'0'..'9'}): break num = j if j > high(args) + 1: - internalError("ropes: invalid format string $" & $j) + internalError(m.config, "ropes: invalid format string $" & $j) add(result, args[j-1]) of 'n': if optLineDir notin gOptions: add(result, rnl) @@ -123,7 +123,7 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope = of 'N': add(result, rnl) inc(i) - else: internalError("ropes: invalid format string $" & frmt[i]) + else: internalError(m.config, "ropes: invalid format string $" & frmt[i]) elif frmt[i] == '#' and frmt[i+1] in IdentStartChars: inc(i) var j = i @@ -148,12 +148,10 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope = template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped = ropecg(m, fmt, args) -var indent = "\t".rope - proc indentLine(p: BProc, r: Rope): Rope = result = r for i in countup(0, p.blocks.len-1): - prepend(result, indent) + prepend(result, "\t".rope) proc appcg(m: BModule, c: var Rope, frmt: FormatStr, args: varargs[Rope]) = @@ -214,7 +212,7 @@ proc genLineDir(p: BProc, t: PNode) = let line = tt.info.safeLineNm if optEmbedOrigSrc in gGlobalOptions: - add(p.s(cpsStmts), ~"//" & tt.info.sourceLine & rnl) + add(p.s(cpsStmts), ~"//" & sourceLine(p.config, tt.info) & rnl) genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line) if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and (p.prc == nil or sfPure notin p.prc.flags): diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index f8167acdca..b439381325 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -148,6 +148,9 @@ type g*: BModuleList ndi*: NdiFile +template config*(m: BModule): ConfigRef = m.g.config +template config*(p: BProc): ConfigRef = p.module.g.config + proc includeHeader*(this: BModule; header: string) = if not this.headerFiles.contains header: this.headerFiles.add header diff --git a/compiler/configuration.nim b/compiler/configuration.nim index 86e3cabf2f..fb28ef6750 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -219,7 +219,7 @@ errExecutionOfProgramFailed: "execution of an external program failed: '$1'", errNotOverloadable: , errInvalidArgForX: "invalid argument for '$1'", errStmtHasNoEffect: "statement has no effect", -errXExpectsTypeOrValue: "'$1' expects a type or value", +, errXExpectsArrayType: "'$1' expects an array type", errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", errExprXAmbiguous: "expression '$1' ambiguous in this context", @@ -229,19 +229,17 @@ errOverOrUnderflow: , errCannotEvalXBecauseIncompletelyDefined: , errChrExpectsRange0_255: "'chr' expects an int in the range 0..255", errDynlibRequiresExportc: "'dynlib' requires 'exportc'", -errUndeclaredFieldX: "undeclared field: '$1'", errNilAccess: "attempt to access a nil address", errIndexOutOfBounds: "index out of bounds", errIndexTypesDoNotMatch: "index types do not match", errBracketsInvalidForType: "'[]' operator invalid for this type", errValueOutOfSetBounds: "value out of set bounds", -errFieldInitTwice: "field initialized twice: '$1'", errFieldNotInit: "field '$1' not initialized", errExprXCannotBeCalled: "expression '$1' cannot be called", errExprHasNoType: "expression has no type", -errExprXHasNoType: "expression '$1' has no type (or is ambiguous)", +errExprXHasNoType:, errCastNotInSafeMode: "'cast' not allowed in safe mode", -errExprCannotBeCastToX: "expression cannot be cast to $1", +errExprCannotBeCastToX: , errCommaOrParRiExpected: "',' or ')' expected", errCurlyLeOrParLeExpected: "'{' or '(' expected", errSectionExpected: "section ('type', 'proc', etc.) expected", @@ -268,10 +266,6 @@ errSizeTooBig: "computing the type's size produced an overflow", errInheritanceOnlyWithEnums: "inheritance only works with an enum", errIllegalRecursionInTypeX:, errCannotInstantiateX: "cannot instantiate: '$1'", -errExprHasNoAddress: "expression has no address", -errXStackEscape: "address of '$1' may not escape its stack frame", -errVarForOutParamNeededX: "for a 'var' type a variable needs to be passed; but '$1' is immutable", -errPureTypeMismatch: "type mismatch", errTypeMismatch: "type mismatch: got <", errButExpected: "but expected one of: ", errButExpectedX: "but expected '$1'", @@ -285,7 +279,7 @@ errImplOfXexpected: , errIllegalConvFromXtoY: , errCannotBindXTwice: "cannot bind parameter '$1' twice", -errInvalidOrderInArrayConstructor: "invalid order in array constructor", +errInvalidOrderInArrayConstructor: , errInvalidOrderInEnumX: "invalid order in enum '$1'", errEnumXHasHoles: "enum '$1' has holes", errExceptExpected: "'except' or 'finally' expected", @@ -310,8 +304,7 @@ errCircumNeedsPointer: "'[]' needs a pointer or reference type", errInvalidExpression: "invalid expression", errInvalidExpressionX: "invalid expression: '$1'", errEnumHasNoValueX: "enum has no value '$1'", -errNamedExprExpected: "named expression expected", -errNamedExprNotAllowed: "named expression not allowed here", +, errNoCommand: "no command given", errInvalidCommandX: "invalid command: '$1'", errXNeedsParamObjectType: , @@ -347,7 +340,6 @@ errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype", errTooManyIterations: "interpretation requires too many iterations; " & "if you are sure this is not a bug in your code edit " & "compiler/vmdef.MaxLoopIterations and rebuild the compiler", -errCannotInterpretNodeX: "cannot evaluate '$1'", errFieldXNotFound: "field '$1' cannot be found", errInvalidConversionFromTypeX: "invalid conversion from type '$1'", errAssertionFailed: "assertion failed", diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 75026d5f44..aabcfd7a6a 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -13,6 +13,8 @@ import ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread, modulegraphs +export createMagic + proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt] proc registerSysType*(g: ModuleGraph; t: PType) = @@ -32,9 +34,10 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = if result.kind == skStub: loadStub(result) if result.kind == skAlias: result = result.owner -proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = - result = newSym(skProc, getIdent(name), nil, unknownLineInfo()) - result.magic = m +when false: + proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = + result = newSym(skProc, getIdent(name), nil, unknownLineInfo()) + result.magic = m when false: let diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 5f741a3b34..da39651864 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -25,7 +25,7 @@ ## - Its dependent module stays the same. ## -import ast, intsets, tables, options, rod, msgs, hashes +import ast, intsets, tables, options, rod, msgs, hashes, idents type ModuleGraph* = ref object @@ -49,6 +49,7 @@ type compilerprocs*: TStrTable exposed*: TStrTable intTypeCache*: array[-5..64, PType] + opContains*, opNot*: PSym proc hash*(x: FileIndex): Hash {.borrow.} @@ -57,6 +58,10 @@ proc hash*(x: FileIndex): Hash {.borrow.} proc stopCompile*(g: ModuleGraph): bool {.inline.} = result = doStopCompile != nil and doStopCompile() +proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = + result = newSym(skProc, getIdent(name), nil, unknownLineInfo()) + result.magic = m + proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = result = ModuleGraph() initStrTable(result.packageSyms) @@ -72,6 +77,8 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = result.methods = @[] initStrTable(result.compilerprocs) initStrTable(result.exposed) + result.opNot = createMagic(result, "not", mNot) + result.opContains = createMagic(result, "contains", mInSet) proc resetAllModules*(g: ModuleGraph) = initStrTable(packageSyms) diff --git a/compiler/sem.nim b/compiler/sem.nim index de0b2d3064..8cb233a056 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -33,7 +33,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semProcBody(c: PContext, n: PNode): PNode proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode -proc changeType(n: PNode, newType: PType, check: bool) +proc changeType(c: PContext; n: PNode, newType: PType, check: bool) proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode proc semTypeNode(c: PContext, n: PNode, prev: PType): PType @@ -86,7 +86,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = else: let x = result.skipConv if x.kind in {nkPar, nkTupleConstr} and formal.kind != tyExpr: - changeType(x, formal, check=true) + changeType(c, x, formal, check=true) else: result = skipHiddenSubConv(result) #result.typ = takeType(formal, arg.typ) @@ -476,7 +476,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) = var prc = c.generics[i].inst.sym if prc.kind in {skProc, skFunc, skMethod, skConverter} and prc.magic == mNone: if prc.ast == nil or prc.ast.sons[bodyPos] == nil: - internalError(prc.info, "no code for " & prc.name.s) + internalError(c.config, prc.info, "no code for " & prc.name.s) else: addSon(n, prc.ast) c.lastGenericIdx = c.generics.len @@ -501,14 +501,14 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = c.importTable = openScope(c) c.importTable.addSym(module) # a module knows itself if sfSystemModule in module.flags: - magicsys.systemModule = module # set global variable! + graph.systemModule = module c.topLevelScope = openScope(c) # don't be verbose unless the module belongs to the main package: if module.owner.id == gMainPackageId: - gNotes = gMainPackageNotes + graph.config.notes = graph.config.mainPackageNotes else: - if gMainPackageNotes == {}: gMainPackageNotes = gNotes - gNotes = ForeignPackageNotes + if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes + graph.config.notes = graph.config.foreignPackageNotes result = c proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext = @@ -517,30 +517,30 @@ proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContex proc replayMethodDefs(graph: ModuleGraph; rd: PRodReader) = for m in items(rd.methods): methodDef(graph, m, true) -proc isImportSystemStmt(n: PNode): bool = - if magicsys.systemModule == nil: return false +proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool = + if g.systemModule == nil: return false case n.kind of nkImportStmt: for x in n: if x.kind == nkIdent: - let f = checkModuleName(x, false) - if f == magicsys.systemModule.info.fileIndex: + let f = checkModuleName(g.config, x, false) + if f == g.systemModule.info.fileIndex: return true of nkImportExceptStmt, nkFromStmt: if n[0].kind == nkIdent: - let f = checkModuleName(n[0], false) - if f == magicsys.systemModule.info.fileIndex: + let f = checkModuleName(g.config, n[0], false) + if f == g.systemModule.info.fileIndex: return true else: discard proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = if n.kind == nkDefer: localError(c.config, n.info, "defer statement not supported at top level") - if c.topStmts == 0 and not isImportSystemStmt(n): + if c.topStmts == 0 and not isImportSystemStmt(c.graph, n): if sfSystemModule notin c.module.flags and n.kind notin {nkEmpty, nkCommentStmt}: - c.importTable.addSym magicsys.systemModule # import the "System" identifier - importAllSymbols(c, magicsys.systemModule) + c.importTable.addSym c.graph.systemModule # import the "System" identifier + importAllSymbols(c, c.graph.systemModule) inc c.topStmts else: inc c.topStmts @@ -566,7 +566,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = result = buildEchoStmt(c, result) if gCmd == cmdIdeTools: appendToModule(c.module, result) - result = transformStmt(c.module, result) + result = transformStmt(c.graph, c.module, result) proc recoverContext(c: PContext) = # clean up in case of a semantic error: We clean up the stacks, etc. This is @@ -579,7 +579,7 @@ proc recoverContext(c: PContext) = proc myProcess(context: PPassContext, n: PNode): PNode = var c = PContext(context) # no need for an expensive 'try' if we stop after the first error anyway: - if msgs.gErrorMax <= 1: + if c.config.errorMax <= 1: result = semStmtAndGenerateGenerics(c, n) else: let oldContextLen = msgs.getInfoContextLen() @@ -602,9 +602,9 @@ proc testExamples(c: PContext) = let inp = toFullPath(c.module.info) let outp = inp.changeFileExt"" & "_examples.nim" renderModule(c.runnableExamples, inp, outp) - let backend = if isDefined("js"): "js" - elif isDefined("cpp"): "cpp" - elif isDefined("objc"): "objc" + let backend = if isDefined(c.config, "js"): "js" + elif isDefined(c.config, "cpp"): "cpp" + elif isDefined(c.config, "objc"): "objc" else: "c" if os.execShellCmd("nim " & backend & " -r " & outp) != 0: quit "[Examples] failed" @@ -618,7 +618,7 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = rawCloseScope(c) # imported symbols; don't check for unused ones! result = newNode(nkStmtList) if n != nil: - internalError(n.info, "n is not nil") #result := n; + internalError(c.config, n.info, "n is not nil") #result := n; addCodeForGenerics(c, result) if c.module.ast != nil: result.add(c.module.ast) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 0ca3fcd4ce..5b5c7f80c8 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -10,12 +10,24 @@ # this module does the semantic checking for expressions # included from sem.nim +const + errExprXHasNoType = "expression '$1' has no type (or is ambiguous)" + errXExpectsTypeOrValue = "'$1' expects a type or value" + errVarForOutParamNeededX = "for a 'var' type a variable needs to be passed; but '$1' is immutable" + errXStackEscape = "address of '$1' may not escape its stack frame" + errExprHasNoAddress = "expression has no address; maybe use 'unsafeAddr'" + errCannotInterpretNodeX = "cannot evaluate '$1'" + errNamedExprExpected = "named expression expected" + errNamedExprNotAllowed = "named expression not allowed here" + errFieldInitTwice = "field initialized twice: '$1'" + errUndeclaredFieldX = "undeclared field: '$1'" + proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}): PNode = - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) pushInfoContext(n.info) - result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags) + result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags) popInfoContext() @@ -31,12 +43,12 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.typ != nil: # XXX tyGenericInst here? if result.typ.kind == tyProc and tfUnresolved in result.typ.flags: - localError(c.config, n.info, errProcHasNoConcreteType, n.renderTree) + localError(c.config, n.info, errProcHasNoConcreteType % n.renderTree) if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyVoid, c) else: - localError(c.config, n.info, errExprXHasNoType, + localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) @@ -47,7 +59,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = #raiseRecoverableError("") result = errorNode(c, n) if result.typ == nil or result.typ == enforceVoidContext: - localError(c.config, n.info, errExprXHasNoType, + localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) else: @@ -59,14 +71,14 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # do not produce another redundant error message: result = errorNode(c, n) if result.typ == nil: - localError(c.config, n.info, errExprXHasNoType, + localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = symChoice(c, n, s, scClosed) -proc inlineConst(n: PNode, s: PSym): PNode {.inline.} = +proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} = result = copyTree(s.ast) if result.isNil: localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value") @@ -172,7 +184,7 @@ proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) = proc semConv(c: PContext, n: PNode): PNode = if sonsLen(n) != 2: - localError(c.config, n.info, errConvNeedsOneArg) + localError(c.config, n.info, "a type conversion takes exactly one argument") return n result = newNodeI(nkConv, n.info) @@ -219,14 +231,14 @@ proc semConv(c: PContext, n: PNode): PNode = of convNotLegal: result = fitNode(c, result.typ, result.sons[1], result.info) if result == nil: - localError(c.config, n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)% + localError(c.config, n.info, "illegal conversion from '$1' to '$2'" % [op.typ.typeToString, result.typ.typeToString]) else: for i in countup(0, sonsLen(op) - 1): let it = op.sons[i] let status = checkConvertible(c, result.typ, it.typ) if status in {convOK, convNotNeedeed}: - markUsed(n.info, it.sym, c.graph.usageSym) + markUsed(c.config, n.info, it.sym, c.graph.usageSym) styleCheckUse(n.info, it.sym) markIndirect(c, it.sym) return it @@ -238,12 +250,12 @@ proc semCast(c: PContext, n: PNode): PNode = let targetType = semTypeNode(c, n.sons[0], nil) let castedExpr = semExprWithType(c, n.sons[1]) if tfHasMeta in targetType.flags: - localError(c.config, n.sons[0].info, errCastToANonConcreteType, $targetType) + localError(c.config, n.sons[0].info, "cannot cast to a non concrete type: '$1'" % $targetType) if not isCastable(targetType, castedExpr.typ): let tar = $targetType let alt = typeToString(targetType, preferDesc) let msg = if tar != alt: tar & "=" & alt else: tar - localError(c.config, n.info, errExprCannotBeCastToX, msg) + localError(c.config, n.info, "expression cannot be cast to " & msg) result = newNodeI(nkCast, n.info) result.typ = targetType addSon(result, copyTree(n.sons[0])) @@ -253,13 +265,13 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = const opToStr: array[mLow..mHigh, string] = ["low", "high"] if sonsLen(n) != 2: - localError(c.config, n.info, errXExpectsTypeOrValue, opToStr[m]) + localError(c.config, n.info, errXExpectsTypeOrValue % opToStr[m]) else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc}) case typ.kind of tySequence, tyString, tyCString, tyOpenArray, tyVarargs: - n.typ = getSysType(tyInt) + n.typ = getSysType(c.graph, n.info, tyInt) of tyArray: n.typ = typ.sons[0] # indextype of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: @@ -271,20 +283,20 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = # that could easily turn into an infinite recursion in semtypinst n.typ = makeTypeFromExpr(c, n.copyTree) else: - localError(c.config, n.info, errInvalidArgForX, opToStr[m]) + localError(c.config, n.info, "invalid argument for: " & opToStr[m]) result = n proc semSizeof(c: PContext, n: PNode): PNode = if sonsLen(n) != 2: - localError(c.config, n.info, errXExpectsTypeOrValue, "sizeof") + localError(c.config, n.info, errXExpectsTypeOrValue % "sizeof") else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) #restoreOldStyleType(n.sons[1]) - n.typ = getSysType(tyInt) + n.typ = getSysType(c.graph, n.info, tyInt) result = n proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = - internalAssert n.sonsLen == 3 and + internalAssert c.config, n.sonsLen == 3 and n[1].typ != nil and n[1].typ.kind == tyTypeDesc and n[2].kind in {nkStrLit..nkTripleStrLit, nkType} @@ -315,10 +327,10 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode = if sonsLen(n) != 3: - localError(c.config, n.info, errXExpectsTwoArguments, "is") + localError(c.config, n.info, "'is' operator takes 2 arguments") result = n - n.typ = getSysType(tyBool) + n.typ = getSysType(c.graph, n.info, tyBool) n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator}) if n[2].kind notin {nkStrLit..nkTripleStrLit}: @@ -340,8 +352,8 @@ proc semOpAux(c: PContext, n: PNode) = for i in countup(1, n.sonsLen-1): var a = n.sons[i] if a.kind == nkExprEqExpr and sonsLen(a) == 2: - var info = a.sons[0].info - a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0], a), info) + let info = a.sons[0].info + a.sons[0] = newIdentNode(considerQuotedIdent(c.config, a.sons[0], a), info) a.sons[1] = semExprWithType(c, a.sons[1], flags) a.typ = a.sons[1].typ else: @@ -358,34 +370,34 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode = for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i]) result = semExpr(c, result) -proc changeType(n: PNode, newType: PType, check: bool) = +proc changeType(c: PContext; n: PNode, newType: PType, check: bool) = case n.kind of nkCurly, nkBracket: for i in countup(0, sonsLen(n) - 1): - changeType(n.sons[i], elemType(newType), check) + changeType(c, n.sons[i], elemType(newType), check) of nkPar, nkTupleConstr: let tup = newType.skipTypes({tyGenericInst, tyAlias, tySink}) if tup.kind != tyTuple: if tup.kind == tyObject: return - globalError(n.info, "no tuple type for constructor") + globalError(c.config, n.info, "no tuple type for constructor") elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: # named tuple? for i in countup(0, sonsLen(n) - 1): var m = n.sons[i].sons[0] if m.kind != nkSym: - globalError(m.info, "invalid tuple constructor") + globalError(c.config, m.info, "invalid tuple constructor") return if tup.n != nil: var f = getSymFromList(tup.n, m.sym.name) if f == nil: - globalError(m.info, "unknown identifier: " & m.sym.name.s) + globalError(c.config, m.info, "unknown identifier: " & m.sym.name.s) return - changeType(n.sons[i].sons[1], f.typ, check) + changeType(c, n.sons[i].sons[1], f.typ, check) else: - changeType(n.sons[i].sons[1], tup.sons[i], check) + changeType(c, n.sons[i].sons[1], tup.sons[i], check) else: for i in countup(0, sonsLen(n) - 1): - changeType(n.sons[i], tup.sons[i], check) + changeType(c, n.sons[i], tup.sons[i], check) when false: var m = n.sons[i] var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i]) @@ -396,7 +408,7 @@ proc changeType(n: PNode, newType: PType, check: bool) = if check and n.kind != nkUInt64Lit: let value = n.intVal if value < firstOrd(newType) or value > lastOrd(newType): - localError(c.config, n.info, errGenerated, "cannot convert " & $value & + localError(c.config, n.info, "cannot convert " & $value & " to " & typeToString(newType)) else: discard n.typ = newType @@ -421,7 +433,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = else: var x = n.sons[0] var lastIndex: BiggestInt = 0 - var indexType = getSysType(tyInt) + var indexType = getSysType(c.graph, n.info, tyInt) if x.kind == nkExprColonExpr and sonsLen(x) == 2: var idx = semConstExpr(c, x.sons[0]) lastIndex = getOrdValue(idx) @@ -438,7 +450,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var idx = semConstExpr(c, x.sons[0]) idx = fitNode(c, indexType, idx, x.info) if lastIndex+1 != getOrdValue(idx): - localError(c.config, x.info, errInvalidOrderInArrayConstructor) + localError(c.config, x.info, "invalid order in array constructor") x = x.sons[1] let xx = semExprWithType(c, x, flags*{efAllowDestructor}) @@ -462,7 +474,7 @@ proc fixAbstractType(c: PContext, n: PNode) = {tyNil, tyTuple, tySet} or it[1].isArrayConstr: var s = skipTypes(it.typ, abstractVar) if s.kind != tyExpr: - changeType(it.sons[1], s, check=true) + changeType(c, it.sons[1], s, check=true) n.sons[i] = it.sons[1] proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult = @@ -477,7 +489,7 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ)) addSon(result, n) if isAssignable(c, n) notin {arLValue, arLocalLValue}: - localError(c.config, n.info, errVarForOutParamNeededX, renderNotLValue(n)) + localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n)) proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = result = n @@ -491,7 +503,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = of nkDotExpr: checkSonsLen(n, 2, c.config) if n.sons[1].kind != nkSym: - internalError(n.info, "analyseIfAddressTaken") + internalError(c.config, n.info, "analyseIfAddressTaken") return if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}: incl(n.sons[1].sym.flags, sfAddrTaken) @@ -600,17 +612,17 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = var call = newNodeIT(nkCall, n.info, n.typ) call.add(n.sons[0]) for i in 1 ..< n.len: - let a = getConstExpr(c.module, n.sons[i]) + let a = getConstExpr(c.module, n.sons[i], c.graph) if a == nil: return n call.add(a) #echo "NOW evaluating at compile time: ", call.renderTree if sfCompileTime in callee.flags: - result = evalStaticExpr(c.module, c.cache, c.graph.config, call, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph, call, c.p.owner) if result.isNil: - localError(c.config, n.info, errCannotInterpretNodeX, renderTree(call)) + localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call)) else: result = fixupTypeAfterEval(c, result, n) else: - result = evalConstExpr(c.module, c.cache, c.graph.config, call) + result = evalConstExpr(c.module, c.cache, c.graph, call) if result.isNil: result = n else: result = fixupTypeAfterEval(c, result, n) #if result != n: @@ -619,9 +631,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = proc semStaticExpr(c: PContext, n: PNode): PNode = let a = semExpr(c, n.sons[0]) if a.findUnresolvedStatic != nil: return a - result = evalStaticExpr(c.module, c.cache, c.graph.config, a, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph, a, c.p.owner) if result.isNil: - localError(c.config, n.info, errCannotInterpretNodeX, renderTree(n)) + localError(c.config, n.info, errCannotInterpretNodeX % renderTree(n)) result = emptyNode else: result = fixupTypeAfterEval(c, result, a) @@ -641,14 +653,14 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, if result != nil: if result.sons[0].kind != nkSym: - internalError("semOverloadedCallAnalyseEffects") + internalError(c.config, "semOverloadedCallAnalyseEffects") return let callee = result.sons[0].sym case callee.kind of skMacro, skTemplate: discard else: if callee.kind == skIterator and callee.id == c.p.owner.id: - localError(c.config, n.info, errRecursiveDependencyX, callee.name.s) + localError(c.config, n.info, errRecursiveDependencyX % callee.name.s) # error correction, prevents endless for loop elimination in transf. # See bug #2051: result.sons[0] = newSymNode(errorSym(c, n)) @@ -736,7 +748,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = return emptyNode else: var hasErrorType = false - var msg = msgKindToString(errTypeMismatch) + var msg = "type mismatch: got <" for i in countup(1, sonsLen(n) - 1): if i > 1: add(msg, ", ") let nt = n.sons[i].typ @@ -745,7 +757,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = hasErrorType = true break if not hasErrorType: - add(msg, ">\n" & msgKindToString(errButExpected) & "\n" & + add(msg, ">\nbut expected one of: \n" & typeToString(n.sons[0].typ)) localError(c.config, n.info, msg) return errorNode(c, n) @@ -790,7 +802,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = proc buildEchoStmt(c: PContext, n: PNode): PNode = # we MUST not check 'n' for semantics again here! But for now we give up: result = newNodeI(nkCall, n.info) - var e = strTableGet(magicsys.systemModule.tab, getIdent"echo") + var e = strTableGet(c.graph.systemModule.tab, getIdent"echo") if e != nil: add(result, newSymNode(e)) else: @@ -857,8 +869,8 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, addSon(check, ast.emptyNode) # make space for access node s = newNodeIT(nkCurly, n.info, setType) for j in countup(0, sonsLen(it) - 2): addSon(s, copyTree(it.sons[j])) - var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool)) - addSon(inExpr, newSymNode(opContains, n.info)) + var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool)) + addSon(inExpr, newSymNode(c.graph.opContains, n.info)) addSon(inExpr, s) addSon(inExpr, copyTree(r.sons[0])) addSon(check, inExpr) @@ -870,12 +882,12 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, if check == nil: check = newNodeI(nkCheckedFieldExpr, n.info) addSon(check, ast.emptyNode) # make space for access node - var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool)) - addSon(inExpr, newSymNode(opContains, n.info)) + var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool)) + addSon(inExpr, newSymNode(c.graph.opContains, n.info)) addSon(inExpr, s) addSon(inExpr, copyTree(r.sons[0])) - var notExpr = newNodeIT(nkCall, n.info, getSysType(tyBool)) - addSon(notExpr, newSymNode(opNot, n.info)) + var notExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool)) + addSon(notExpr, newSymNode(c.graph.opNot, n.info)) addSon(notExpr, inExpr) addSon(check, notExpr) return @@ -937,12 +949,12 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = let s = getGenSym(c, sym) case s.kind of skConst: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, tyTuple, tySet, tyUInt..tyUInt64: - if s.magic == mNone: result = inlineConst(n, s) + if s.magic == mNone: result = inlineConst(c, n, s) else: result = newSymNode(s, n.info) of tyArray, tySequence: # Consider:: @@ -955,13 +967,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = # It is clear that ``[]`` means two totally different things. Thus, we # copy `x`'s AST into each context, so that the type fixup phase can # deal with two different ``[]``. - if s.ast.len == 0: result = inlineConst(n, s) + if s.ast.len == 0: result = inlineConst(c, n, s) else: result = newSymNode(s, n.info) else: result = newSymNode(s, n.info) of skMacro: if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: @@ -969,13 +981,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = of skTemplate: if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or sfCustomPragma in sym.flags: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: result = semTemplateExpr(c, n, s, flags) of skParam: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil: # XXX see the hack in sigmatch.nim ... @@ -985,19 +997,19 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = # gensym'ed parameters that nevertheless have been forward declared # need a special fixup: let realParam = c.p.owner.typ.n[s.position+1] - internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam + internalAssert c.config, realParam.kind == nkSym and realParam.sym.kind == skParam return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info) elif c.p.owner.kind == skMacro: # gensym'ed macro parameters need a similar hack (see bug #1944): var u = searchInScopes(c, s.name) - internalAssert u != nil and u.kind == skParam and u.owner == s.owner + internalAssert c.config, u != nil and u.kind == skParam and u.owner == s.owner return newSymNode(u, n.info) result = newSymNode(s, n.info) of skVar, skLet, skResult, skForVar: if s.magic == mNimvm: localError(c.config, n.info, "illegal context for 'nimvm' magic") - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) # We cannot check for access to outer vars for example because it's still @@ -1015,7 +1027,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = n.typ = s.typ return n of skType: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) if s.typ.kind == tyStatic and s.typ.n != nil: return s.typ.n @@ -1037,7 +1049,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if f != nil and fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? doAssert f == s - markUsed(n.info, f, c.graph.usageSym) + markUsed(c.config, n.info, f, c.graph.usageSym) styleCheckUse(n.info, f) result = newNodeIT(nkDotExpr, n.info, f.typ) result.add makeDeref(newSymNode(p.selfSym)) @@ -1050,11 +1062,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if ty.sons[0] == nil: break ty = skipTypes(ty.sons[0], skipPtrs) # old code, not sure if it's live code: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) @@ -1076,14 +1088,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = symChoice(c, n, s, scClosed) if result.kind == nkSym: result = semSym(c, n, s, flags) else: - markUsed(n.sons[1].info, s, c.graph.usageSym) + markUsed(c.config, n.sons[1].info, s, c.graph.usageSym) result = semSym(c, n, s, flags) styleCheckUse(n.sons[1].info, s) return n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType}) #restoreOldStyleType(n.sons[0]) - var i = considerQuotedIdent(n.sons[1], n) + var i = considerQuotedIdent(c.config, n.sons[1], n) var ty = n.sons[0].typ var f: PSym = nil result = nil @@ -1140,7 +1152,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = newSymNode(f) result.info = n.info result.typ = ty - markUsed(n.info, f, c.graph.usageSym) + markUsed(c.config, n.info, f, c.graph.usageSym) styleCheckUse(n.info, f) return of tyObject, tyTuple: @@ -1171,7 +1183,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if f != nil: 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, c.graph.usageSym) + markUsed(c.config, n.sons[1].info, f, c.graph.usageSym) styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) # we now have the correct field @@ -1185,7 +1197,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = elif ty.kind == tyTuple and ty.n != nil: f = getSymFromList(ty.n, i) if f != nil: - markUsed(n.sons[1].info, f, c.graph.usageSym) + markUsed(c.config, n.sons[1].info, f, c.graph.usageSym) styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) @@ -1203,7 +1215,7 @@ proc dotTransformation(c: PContext, n: PNode): PNode = addSon(result, n.sons[1]) addSon(result, copyTree(n[0])) else: - var i = considerQuotedIdent(n.sons[1], n) + var i = considerQuotedIdent(c.config, n.sons[1], n) result = newNodeI(nkDotCall, n.info) result.flags.incl nfDotField addSon(result, newIdentNode(i, n[1].info)) @@ -1254,7 +1266,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = for i in countup(1, sonsLen(n) - 1): n.sons[i] = semExprWithType(c, n.sons[i], flags*{efInTypeof, efDetermineType}) - var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt) + var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(c.graph, n.info, tyInt) var arg = indexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1]) if arg != nil: n.sons[1] = arg @@ -1277,7 +1289,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = {tyInt..tyInt64}: var idx = getOrdValue(n.sons[1]) if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)] - else: localError(c.config, n.info, errInvalidIndexValueForTuple) + else: localError(c.config, n.info, "invalid index value for tuple subscript") result = n else: result = nil @@ -1317,7 +1329,7 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]")) proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = - var id = considerQuotedIdent(a[1], a) + var id = considerQuotedIdent(c.config, a[1], a) var setterId = newIdentNode(getIdent(id.s & '='), n.info) # a[0] is already checked for semantics, that does ``builtinFieldAccess`` # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for @@ -1354,7 +1366,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = let valid = isAssignable(c, n) if valid != arLValue: if valid == arLocalLValue: - localError(c.config, n.info, errXStackEscape, renderTree(n, {renderNoComments})) + localError(c.config, n.info, errXStackEscape % renderTree(n, {renderNoComments})) elif not isLent: localError(c.config, n.info, errExprHasNoAddress) result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ)) @@ -1426,7 +1438,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = isAssignable(c, a) == arNone) or skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}: # Direct assignment to a discriminant is allowed! - localError(c.config, a.info, errXCannotBeAssignedTo, + localError(c.config, a.info, errXCannotBeAssignedTo % renderTree(a, {renderNoComments})) else: let @@ -1442,12 +1454,12 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass: rhsTyp = rhsTyp.lastSon if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}: - internalAssert c.p.resultSym != nil + internalAssert c.config, c.p.resultSym != nil lhs.typ = rhsTyp c.p.resultSym.typ = rhsTyp c.p.owner.typ.sons[0] = rhsTyp else: - typeMismatch(n.info, lhs.typ, rhsTyp) + typeMismatch(c.config, n.info, lhs.typ, rhsTyp) n.sons[1] = fitNode(c, le, rhs, n.info) if destructor notin c.features: @@ -1479,7 +1491,7 @@ proc semReturn(c: PContext, n: PNode): PNode = else: localError(c.config, n.info, errNoReturnTypeDeclared) else: - localError(c.config, n.info, errXNotAllowedHere, "\'return\'") + localError(c.config, n.info, "'return' not allowed here") proc semProcBody(c: PContext, n: PNode): PNode = openScope(c) @@ -1551,7 +1563,7 @@ proc semYield(c: PContext, n: PNode): PNode = if restype != nil: if restype.kind != tyExpr: n.sons[0] = fitNode(c, restype, n.sons[0], n.info) - if n.sons[0].typ == nil: internalError(n.info, "semYield") + if n.sons[0].typ == nil: internalError(c.config, n.info, "semYield") if resultTypeIsInferrable(restype): let inferred = n.sons[0].typ @@ -1579,19 +1591,19 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = checkSonsLen(n, 2, c.config) var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope) if m != nil and m.kind == skModule: - let ident = considerQuotedIdent(n[1], n) + let ident = considerQuotedIdent(c.config, n[1], n) if m == c.module: result = strTableGet(c.topLevelScope.symbols, ident) else: result = strTableGet(m.tab, ident) of nkAccQuoted: - result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope) + result = lookUpForDefined(c, considerQuotedIdent(c.config, n), onlyCurrentScope) of nkSym: result = n.sym of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym else: - localError(c.config, n.info, errIdentifierExpected, renderTree(n)) + localError(c.config, n.info, "identifier expected, but got: " & renderTree(n)) result = nil proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = @@ -1601,12 +1613,12 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = if not onlyCurrentScope and considerQuotedIdent(c.config, n[0], n).s == "defined": if n.sons[1].kind != nkIdent: localError(c.config, n.info, "obsolete usage of 'defined', use 'declared' instead") - elif condsyms.isDefined(n.sons[1].ident): + elif isDefined(c.config, n.sons[1].ident.s): result.intVal = 1 elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: result.intVal = 1 result.info = n.info - result.typ = getSysType(tyBool) + result.typ = getSysType(c.graph, n.info, tyBool) proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym = ## The argument to the proc should be nkCall(...) or similar @@ -1618,12 +1630,12 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym = return errorSym(c, n[0]) if expandedSym.kind notin {skMacro, skTemplate}: - localError(c.config, n.info, errXisNoMacroOrTemplate, expandedSym.name.s) + localError(c.config, n.info, "'$1' is not a macro or template" % expandedSym.name.s) return errorSym(c, n[0]) result = expandedSym else: - localError(c.config, n.info, errXisNoMacroOrTemplate, n.renderTree) + localError(c.config, n.info, "'$1' is not a macro or template" % n.renderTree) result = errorSym(c, n) proc expectString(c: PContext, n: PNode): string = @@ -1633,10 +1645,6 @@ proc expectString(c: PContext, n: PNode): string = else: localError(c.config, n.info, errStringLiteralExpected) -proc getMagicSym(magic: TMagic): PSym = - result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo) - result.magic = magic - proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym = result = newSym(kind, c.cache.idAnon, getCurrOwner(c), info) result.flags = {sfGenSym} @@ -1649,7 +1657,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = if expandedSym.kind == skError: return n macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) - markUsed(n.info, expandedSym, c.graph.usageSym) + markUsed(c.config, n.info, expandedSym, c.graph.usageSym) styleCheckUse(n.info, expandedSym) if isCallExpr(macroCall): @@ -1674,7 +1682,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = else: let info = macroCall.sons[0].info macroCall.sons[0] = newSymNode(cand, info) - markUsed(info, cand, c.graph.usageSym) + markUsed(c.config, info, cand, c.graph.usageSym) styleCheckUse(info, cand) # we just perform overloading resolution here: @@ -1682,12 +1690,11 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = else: localError(c.config, n.info, "getAst takes a call, but got " & n.renderTree) # Preserve the magic symbol in order to be handled in evals.nim - internalAssert n.sons[0].sym.magic == mExpandToAst + internalAssert c.config, n.sons[0].sym.magic == mExpandToAst #n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType if n.kind == nkStmtList and n.len == 1: result = n[0] else: result = n - result.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode" - else: sysTypeFromName"PNimrodNode" + result.typ = sysTypeFromName(c.graph, n.info, "NimNode") proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, flags: TExprFlags = {}): PNode = @@ -1697,7 +1704,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, else: result = semDirectOp(c, n, flags) -proc processQuotations(n: var PNode, op: string, +proc processQuotations(c: PContext; n: var PNode, op: string, quotes: var seq[PNode], ids: var seq[PNode]) = template returnQuote(q) = @@ -1718,10 +1725,10 @@ proc processQuotations(n: var PNode, op: string, returnQuote n[0] for i in 0 ..< n.safeLen: - processQuotations(n.sons[i], op, quotes, ids) + processQuotations(c, n.sons[i], op, quotes, ids) proc semQuoteAst(c: PContext, n: PNode): PNode = - internalAssert n.len == 2 or n.len == 3 + internalAssert c.config, n.len == 2 or n.len == 3 # We transform the do block into a template with a param for # each interpolation. We'll pass this template to getAst. var @@ -1736,7 +1743,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = if quotedBlock.kind != nkStmtList: localError(c.config, n.info, errXExpected, "block") - processQuotations(quotedBlock, op, quotes, ids) + processQuotations(c, quotedBlock, op, quotes, ids) var dummyTemplate = newProcNode( nkTemplateDef, quotedBlock.info, quotedBlock, @@ -1744,27 +1751,27 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = if ids.len > 0: dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info) - dummyTemplate[paramsPos].add getSysSym("typed").newSymNode # return type - ids.add getSysSym("untyped").newSymNode # params type + dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "typed").newSymNode # return type + ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type ids.add emptyNode # no default value dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids) var tmpl = semTemplateDef(c, dummyTemplate) quotes[0] = tmpl[namePos] result = newNode(nkCall, n.info, @[ - getMagicSym(mExpandToAst).newSymNode, + createMagic(c.graph, "getAst", mExpandToAst).newSymNode, newNode(nkCall, n.info, quotes)]) result = semExpandToAst(c, result) proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # watch out, hacks ahead: - let oldErrorCount = msgs.gErrorCounter - let oldErrorMax = msgs.gErrorMax + let oldErrorCount = c.config.errorCounter + let oldErrorMax = c.config.errorMax let oldCompilesId = c.compilesContextId inc c.compilesContextIdGenerator c.compilesContextId = c.compilesContextIdGenerator # do not halt after first error: - msgs.gErrorMax = high(int) + c.config.errorMax = high(int) # open a scope for temporary symbol inclusions: let oldScope = c.currentScope @@ -1783,7 +1790,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = var err: string try: result = semExpr(c, n, flags) - if msgs.gErrorCounter != oldErrorCount: result = nil + if c.config.errorCounter != oldErrorCount: result = nil except ERecoverableError: discard # undo symbol table changes (as far as it's possible): @@ -1797,8 +1804,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = setLen(c.graph.owners, oldOwnerLen) c.currentScope = oldScope errorOutputs = oldErrorOutputs - msgs.gErrorCounter = oldErrorCount - msgs.gErrorMax = oldErrorMax + c.config.errorCounter = oldErrorCount + c.config.errorMax = oldErrorMax proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = # we replace this node by a 'true' or 'false' node: @@ -1806,7 +1813,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil)) result.info = n.info - result.typ = getSysType(tyBool) + result.typ = getSysType(c.graph, n.info, tyBool) proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode = if sonsLen(n) == 3: @@ -1821,15 +1828,15 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode = proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType = result = newType(tyGenericInvocation, c.module) - addSonSkipIntLit(result, magicsys.getCompilerProc("FlowVar").typ) + addSonSkipIntLit(result, magicsys.getCompilerProc(c.graph, "FlowVar").typ) addSonSkipIntLit(result, t) result = instGenericContainer(c, info, result, allowMetaTypes = false) proc instantiateCreateFlowVarCall(c: PContext; t: PType; info: TLineInfo): PSym = - let sym = magicsys.getCompilerProc("nimCreateFlowVar") + let sym = magicsys.getCompilerProc(c.graph, "nimCreateFlowVar") if sym == nil: - localError(c.config, info, errSystemNeeds, "nimCreateFlowVar") + localError(c.config, info, "system needs: nimCreateFlowVar") var bindings: TIdTable initIdTable(bindings) bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t) @@ -1879,8 +1886,8 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mQuoteAst: result = semQuoteAst(c, n) of mAstToStr: checkSonsLen(n, 2, c.config) - result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) - result.typ = getSysType(tyString) + result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph) + result.typ = getSysType(c.graph, n.info, tyString) of mParallel: if parallel notin c.features: localError(c.config, n.info, "use the {.experimental.} pragma to enable 'parallel'") @@ -2072,7 +2079,7 @@ type TParKind = enum paNone, paSingle, paTupleFields, paTuplePositions -proc checkPar(n: PNode): TParKind = +proc checkPar(c: PContext; n: PNode): TParKind = var length = sonsLen(n) if length == 0: result = paTuplePositions # () @@ -2106,7 +2113,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident else: id = n.sons[i].sons[0].sym.name if containsOrIncl(ids, id.id): - localError(c.config, n.sons[i].info, errFieldInitTwice, id.s) + localError(c.config, n.sons[i].info, errFieldInitTwice % id.s) n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1], flags*{efAllowDestructor}) var f = newSymS(skField, n.sons[i].sons[0], c) @@ -2225,39 +2232,39 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkEmpty, nkNone, nkCommentStmt, nkType: discard of nkNilLit: - if result.typ == nil: result.typ = getSysType(tyNil) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyNil) of nkIntLit: - if result.typ == nil: setIntLitType(result) + if result.typ == nil: setIntLitType(c.graph, result) of nkInt8Lit: - if result.typ == nil: result.typ = getSysType(tyInt8) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt8) of nkInt16Lit: - if result.typ == nil: result.typ = getSysType(tyInt16) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt16) of nkInt32Lit: - if result.typ == nil: result.typ = getSysType(tyInt32) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt32) of nkInt64Lit: - if result.typ == nil: result.typ = getSysType(tyInt64) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt64) of nkUIntLit: - if result.typ == nil: result.typ = getSysType(tyUInt) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt) of nkUInt8Lit: - if result.typ == nil: result.typ = getSysType(tyUInt8) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt8) of nkUInt16Lit: - if result.typ == nil: result.typ = getSysType(tyUInt16) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt16) of nkUInt32Lit: - if result.typ == nil: result.typ = getSysType(tyUInt32) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt32) of nkUInt64Lit: - if result.typ == nil: result.typ = getSysType(tyUInt64) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt64) #of nkFloatLit: # if result.typ == nil: result.typ = getFloatLitType(result) of nkFloat32Lit: - if result.typ == nil: result.typ = getSysType(tyFloat32) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat32) of nkFloat64Lit, nkFloatLit: - if result.typ == nil: result.typ = getSysType(tyFloat64) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat64) of nkFloat128Lit: - if result.typ == nil: result.typ = getSysType(tyFloat128) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat128) of nkStrLit..nkTripleStrLit: - if result.typ == nil: result.typ = getSysType(tyString) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyString) of nkCharLit: - if result.typ == nil: result.typ = getSysType(tyChar) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyChar) of nkDotExpr: result = semFieldAccess(c, n, flags) if result.kind == nkDotCall: @@ -2341,7 +2348,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = var expr = n[0] pragma = n[1] - pragmaName = considerQuotedIdent(pragma[0]) + pragmaName = considerQuotedIdent(c.config, pragma[0]) flags = flags case whichKeyword(pragmaName) @@ -2349,11 +2356,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = flags.incl efExplain else: # what other pragmas are allowed for expressions? `likely`, `unlikely` - invalidPragma(n) + invalidPragma(c, n) result = semExpr(c, n[0], flags) of nkPar, nkTupleConstr: - case checkPar(n) + case checkPar(c, n) of paNone: result = errorNode(c, n) of paTuplePositions: var tupexp = semTuplePositionsConstr(c, n, flags) @@ -2433,19 +2440,19 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # # works: if c.currentScope.depthLevel > 2 + c.compilesContextId: - localError(c.config, n.info, errXOnlyAtModuleScope, "import") + localError(c.config, n.info, errXOnlyAtModuleScope % "import") result = evalImport(c, n) of nkImportExceptStmt: - if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "import") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "import") result = evalImportExcept(c, n) of nkFromStmt: - if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "from") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "from") result = evalFrom(c, n) of nkIncludeStmt: - #if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "include") + #if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "include") result = evalInclude(c, n) of nkExportStmt, nkExportExceptStmt: - if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "export") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export") result = semExport(c, n) of nkPragmaBlock: result = semPragmaBlock(c, n) @@ -2454,7 +2461,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkDefer: n.sons[0] = semExpr(c, n.sons[0]) if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]): - localError(c.config, n.info, errGenerated, "'defer' takes a 'void' expression") + localError(c.config, n.info, "'defer' takes a 'void' expression") #localError(c.config, n.info, errGenerated, "'defer' not allowed in this context") of nkGotoState, nkState: if n.len != 1 and n.len != 2: illFormedAst(n, c.config) @@ -2462,6 +2469,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = n.sons[i] = semExpr(c, n.sons[i]) of nkComesFrom: discard "ignore the comes from information for now" else: - localError(c.config, n.info, errInvalidExpressionX, + localError(c.config, n.info, "invalid expression: " & renderTree(n, {renderNoComments})) if result != nil: incl(result.flags, nfSem) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 49dfb58f91..93d56b6031 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -64,7 +64,7 @@ proc semAsgnOpr(c: PContext; n: PNode): PNode = proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode = var r = isPartOf(n[1], n[2]) - result = newIntNodeT(ord(r), n) + result = newIntNodeT(ord(r), n, c.graph) proc expectIntLit(c: PContext, n: PNode): int = let x = c.semConstExpr(c, n) @@ -77,11 +77,11 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode = let idx = expectIntLit(c, n.sons[1]) let useFullPaths = expectIntLit(c, n.sons[2]) let info = getInfoContext(idx) - var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString)) + var filename = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString)) filename.strVal = if useFullPaths != 0: info.toFullPath else: info.toFilename - var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt)) + var line = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt)) line.intVal = toLinenumber(info) - var column = newNodeIT(nkIntLit, n.info, getSysType(tyInt)) + var column = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt)) column.intVal = toColumn(info) result.add(filename) result.add(line) @@ -110,10 +110,10 @@ proc uninstantiate(t: PType): PType = of tyCompositeTypeClass: uninstantiate t.sons[1] else: t -proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode = +proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym): PNode = const skippedTypes = {tyTypeDesc, tyAlias, tySink} let trait = traitCall[0] - internalAssert trait.kind == nkSym + internalAssert c.config, trait.kind == nkSym var operand = operand.skipTypes(skippedTypes) template operand2: PType = @@ -151,19 +151,19 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode = let t = operand.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink, tyInferred}) let complexObj = containsGarbageCollectedRef(t) or hasDestructor(t) - result = newIntNodeT(ord(not complexObj), traitCall) + result = newIntNodeT(ord(not complexObj), traitCall, c.graph) else: localError(c.config, traitCall.info, "unknown trait") result = emptyNode proc semTypeTraits(c: PContext, n: PNode): PNode = - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) let t = n.sons[1].typ - internalAssert t != nil and t.kind == tyTypeDesc + internalAssert c.config, t != nil and t.kind == tyTypeDesc if t.sonsLen > 0: # This is either a type known to sem or a typedesc # param to a regular proc (again, known at instantiation) - result = evalTypeTrait(n, t, getCurrOwner(c)) + result = evalTypeTrait(c, n, t, getCurrOwner(c)) else: # a typedesc variable, pass unmodified to evals result = n @@ -221,9 +221,9 @@ proc semOf(c: PContext, n: PNode): PNode = let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc}) if x.kind == tyTypeDesc or y.kind != tyTypeDesc: - localError(c.config, n.info, errXExpectsObjectTypes, "of") + localError(c.config, n.info, "'of' takes object types") elif b.kind != tyObject or a.kind != tyObject: - localError(c.config, n.info, errXExpectsObjectTypes, "of") + localError(c.config, n.info, "'of' takes object types") else: let diff = inheritanceDiff(a, b) # | returns: 0 iff `a` == `b` @@ -232,26 +232,26 @@ proc semOf(c: PContext, n: PNode): PNode = # | returns: `maxint` iff `a` and `b` are not compatible at all if diff <= 0: # optimize to true: - message(n.info, hintConditionAlwaysTrue, renderTree(n)) + message(c.config, n.info, hintConditionAlwaysTrue, renderTree(n)) result = newIntNode(nkIntLit, 1) result.info = n.info - result.typ = getSysType(tyBool) + result.typ = getSysType(c.graph, n.info, tyBool) return result elif diff == high(int): - localError(c.config, n.info, errXcanNeverBeOfThisSubtype, typeToString(a)) + localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a)) else: - localError(c.config, n.info, errXExpectsTwoArguments, "of") - n.typ = getSysType(tyBool) + localError(c.config, n.info, "'of' takes 2 arguments") + n.typ = getSysType(c.graph, n.info, tyBool) result = n proc magicsAfterOverloadResolution(c: PContext, n: PNode, flags: TExprFlags): PNode = case n[0].sym.magic of mAddr: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr") of mTypeOf: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) result = semTypeOf(c, n.sons[1]) of mArrGet: result = semArrGet(c, n, flags) of mArrPut: result = semArrPut(c, n, flags) @@ -263,8 +263,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mIsPartOf: result = semIsPartOf(c, n, flags) of mTypeTrait: result = semTypeTraits(c, n) of mAstToStr: - result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) - result.typ = getSysType(tyString) + result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph) + result.typ = getSysType(c.graph, n.info, tyString) of mInstantiationInfo: result = semInstantiationInfo(c, n) of mOrd: result = semOrd(c, n) of mOf: result = semOf(c, n) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index a47bc24ed3..1e0802953e 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -39,32 +39,32 @@ proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) = of initUnknown: discard -proc invalidObjConstr(n: PNode) = +proc invalidObjConstr(c: PContext, n: PNode) = if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s[0] == ':': localError(c.config, n.info, "incorrect object construction syntax; use a space after the colon") else: localError(c.config, n.info, "incorrect object construction syntax") -proc locateFieldInInitExpr(field: PSym, initExpr: PNode): PNode = +proc locateFieldInInitExpr(c: PContext, field: PSym, initExpr: PNode): PNode = # Returns the assignment nkExprColonExpr node or nil let fieldId = field.name.id for i in 1 ..< initExpr.len: let assignment = initExpr[i] if assignment.kind != nkExprColonExpr: - invalidObjConstr(assignment) + invalidObjConstr(c, assignment) continue - if fieldId == considerQuotedIdent(assignment[0]).id: + if fieldId == considerQuotedIdent(c.config, assignment[0]).id: return assignment proc semConstrField(c: PContext, flags: TExprFlags, field: PSym, initExpr: PNode): PNode = - let assignment = locateFieldInInitExpr(field, initExpr) + let assignment = locateFieldInInitExpr(c, field, initExpr) if assignment != nil: if nfSem in assignment.flags: return assignment[1] if not fieldVisible(c, field): localError(c.config, initExpr.info, - "the field '$1' is not accessible.", [field.name.s]) + "the field '$1' is not accessible." % [field.name.s]) return var initValue = semExprFlagDispatched(c, assignment[1], flags) @@ -101,25 +101,25 @@ iterator directFieldsInRecList(recList: PNode): PNode = if recList.kind == nkSym: yield recList else: - internalAssert recList.kind == nkRecList + doAssert recList.kind == nkRecList for field in recList: if field.kind != nkSym: continue yield field template quoteStr(s: string): string = "'" & s & "'" -proc fieldsPresentInInitExpr(fieldsRecList, initExpr: PNode): string = +proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): string = result = "" for field in directFieldsInRecList(fieldsRecList): - let assignment = locateFieldInInitExpr(field.sym, initExpr) + let assignment = locateFieldInInitExpr(c, field.sym, initExpr) if assignment != nil: if result.len != 0: result.add ", " result.add field.sym.name.s.quoteStr -proc missingMandatoryFields(fieldsRecList, initExpr: PNode): string = +proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string = for r in directFieldsInRecList(fieldsRecList): if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}: - let assignment = locateFieldInInitExpr(r.sym, initExpr) + let assignment = locateFieldInInitExpr(c, r.sym, initExpr) if assignment == nil: if result == nil: result = r.sym.name.s @@ -127,8 +127,8 @@ proc missingMandatoryFields(fieldsRecList, initExpr: PNode): string = result.add ", " result.add r.sym.name.s -proc checkForMissingFields(recList, initExpr: PNode) = - let missing = missingMandatoryFields(recList, initExpr) +proc checkForMissingFields(c: PContext, recList, initExpr: PNode) = + let missing = missingMandatoryFields(c, recList, initExpr) if missing != nil: localError(c.config, initExpr.info, "fields not initialized: $1.", [missing]) @@ -146,14 +146,14 @@ proc semConstructFields(c: PContext, recNode: PNode, template fieldsPresentInBranch(branchIdx: int): string = let branch = recNode[branchIdx] let fields = branch[branch.len - 1] - fieldsPresentInInitExpr(fields, initExpr) + fieldsPresentInInitExpr(c, fields, initExpr) template checkMissingFields(branchNode: PNode) = let fields = branchNode[branchNode.len - 1] - checkForMissingFields(fields, initExpr) + checkForMissingFields(c, fields, initExpr) - let discriminator = recNode.sons[0]; - internalAssert discriminator.kind == nkSym + let discriminator = recNode.sons[0] + internalAssert c.config, discriminator.kind == nkSym var selectedBranch = -1 for i in 1 ..< recNode.len: @@ -165,8 +165,8 @@ proc semConstructFields(c: PContext, recNode: PNode, let prevFields = fieldsPresentInBranch(selectedBranch) let currentFields = fieldsPresentInBranch(i) localError(c.config, initExpr.info, - "The fields ($1) and ($2) cannot be initialized together, " & - "because they are from conflicting branches in the case object.", + ("The fields '$1' and '$2' cannot be initialized together, " & + "because they are from conflicting branches in the case object.") % [prevFields, currentFields]) result = initConflict else: @@ -180,8 +180,8 @@ proc semConstructFields(c: PContext, recNode: PNode, if discriminatorVal == nil: let fields = fieldsPresentInBranch(selectedBranch) localError(c.config, initExpr.info, - "you must provide a compile-time value for the discriminator '$1' " & - "in order to prove that it's safe to initialize $2.", + ("you must provide a compile-time value for the discriminator '$1' " & + "in order to prove that it's safe to initialize $2.") % [discriminator.sym.name.s, fields]) mergeInitStatus(result, initNone) else: @@ -219,7 +219,7 @@ proc semConstructFields(c: PContext, recNode: PNode, # value was given to the discrimator. We can assume that it will be # initialized to zero and this will select a particular branch as # a result: - let matchedBranch = recNode.pickCaseBranch newIntLit(0) + let matchedBranch = recNode.pickCaseBranch newIntLit(c.graph, initExpr.info, 0) checkMissingFields matchedBranch else: result = initPartial @@ -239,20 +239,17 @@ proc semConstructFields(c: PContext, recNode: PNode, result = if e != nil: initFull else: initNone else: - internalAssert false + internalAssert c.config, false proc semConstructType(c: PContext, initExpr: PNode, t: PType, flags: TExprFlags): InitStatus = var t = t result = initUnknown - while true: let status = semConstructFields(c, t.n, initExpr, flags) mergeInitStatus(result, status) - if status in {initPartial, initNone, initUnknown}: - checkForMissingFields t.n, initExpr - + checkForMissingFields c, t.n, initExpr let base = t.sons[0] if base == nil: break t = skipTypes(base, skipPtrs) @@ -296,17 +293,16 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = let field = result[i] if nfSem notin field.flags: if field.kind != nkExprColonExpr: - invalidObjConstr(field) + invalidObjConstr(c, field) continue - let id = considerQuotedIdent(field[0]) + let id = considerQuotedIdent(c.config, field[0]) # This node was not processed. There are two possible reasons: # 1) It was shadowed by a field with the same name on the left for j in 1 ..< i: - let prevId = considerQuotedIdent(result[j][0]) + let prevId = considerQuotedIdent(c.config, result[j][0]) if prevId.id == id.id: - localError(c.config, field.info, errFieldInitTwice, id.s) + localError(c.config, field.info, errFieldInitTwice % id.s) return # 2) No such field exists in the constructed type - localError(c.config, field.info, errUndeclaredFieldX, id.s) + localError(c.config, field.info, errUndeclaredFieldX % id.s) return - diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f09fad5885..0df3ee1c4d 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -338,10 +338,10 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = result.info = n.info result.typ = typ else: - changeType(r1, typ, check=true) + changeType(c, r1, typ, check=true) result = r1 elif not sameType(result.typ, typ): - changeType(result, typ, check=false) + changeType(c, result, typ, check=false) proc findShadowedVar(c: PContext, v: PSym): PSym = for scope in walkScopes(c.currentScope.parent): From 1284827df2f25d1d387d8325ef49248f22879db1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 23:45:51 +0200 Subject: [PATCH 191/214] C code generator compiles again --- compiler/ccgcalls.nim | 18 ++--- compiler/ccgexprs.nim | 138 ++++++++++++++++++------------------- compiler/ccgliterals.nim | 6 +- compiler/ccgstmts.nim | 39 +++++------ compiler/ccgthreadvars.nim | 6 +- compiler/ccgtrav.nim | 14 ++-- compiler/ccgtypes.nim | 66 +++++++++--------- compiler/ccgutils.nim | 2 +- compiler/cgen.nim | 110 +++++++++++++++-------------- compiler/cgendata.nim | 7 +- compiler/configuration.nim | 4 +- 11 files changed, 208 insertions(+), 202 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 2ddc88509b..7d355db5fd 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -116,7 +116,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = else: result = "$1->data+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)] else: - internalError("openArrayLoc: " & typeToString(a.t)) + internalError(p.config, "openArrayLoc: " & typeToString(a.t)) else: initLocExpr(p, n, a) case skipTypes(a.t, abstractVar).kind @@ -137,8 +137,8 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = of tyArray: result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))] else: - internalError("openArrayLoc: " & typeToString(a.t)) - else: internalError("openArrayLoc: " & typeToString(a.t)) + internalError(p.config, "openArrayLoc: " & typeToString(a.t)) + else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} = var a: TLoc @@ -273,7 +273,7 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) else: if tfVarargs notin typ.flags: - localError(ri.info, "wrong argument count") + localError(p.config, ri.info, "wrong argument count") result = nil else: result = genArgNoParam(p, ri.sons[i]) @@ -337,7 +337,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = # for better or worse c2nim translates the 'this' argument to a 'var T'. # However manual wrappers may also use 'ptr T'. In any case we support both # for convenience. - internalAssert i < sonsLen(typ) + internalAssert p.config, i < sonsLen(typ) assert(typ.n.sons[i].kind == nkSym) # if the parameter is lying (tyVar) and thus we required an additional deref, # skip the deref: @@ -394,7 +394,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope = result.add genOtherArg(p, ri, k, typ) result.add(~")") else: - localError(ri.info, "call expression expected for C++ pattern") + localError(p.config, ri.info, "call expression expected for C++ pattern") inc i elif pat[i+1] == '.': result.add genThisArg(p, ri, j, typ) @@ -432,7 +432,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = assert(sonsLen(typ) == sonsLen(typ.n)) # don't call '$' here for efficiency: let pat = ri.sons[0].sym.loc.r.data - internalAssert pat != nil + internalAssert p.config, pat != nil if pat.contains({'#', '(', '@', '\''}): var pl = genPatternCall(p, ri, pat, typ) # simpler version of 'fixupCall' that works with the pl+params combination: @@ -481,7 +481,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = # don't call '$' here for efficiency: let pat = ri.sons[0].sym.loc.r.data - internalAssert pat != nil + internalAssert p.config, pat != nil var start = 3 if ' ' in pat: start = 1 @@ -501,7 +501,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = for i in countup(start, length-1): assert(sonsLen(typ) == sonsLen(typ.n)) if i >= sonsLen(typ): - internalError(ri.info, "varargs for objective C method?") + internalError(p.config, ri.info, "varargs for objective C method?") assert(typ.n.sons[i].kind == nkSym) var param = typ.n.sons[i].sym add(pl, ~" ") diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 96f9265f17..a78a96c13e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -31,7 +31,7 @@ proc intLiteral(i: BiggestInt): Rope = result = ~"(IL64(-9223372036854775807) - IL64(1))" proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = - if ty == nil: internalError(n.info, "genLiteral: ty is nil") + if ty == nil: internalError(p.config, n.info, "genLiteral: ty is nil") case n.kind of nkCharLit..nkUInt64Lit: case skipTypes(ty, abstractVarRange).kind @@ -76,7 +76,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = of nkFloat32Lit: result = rope(n.floatVal.toStrMaxPrecision("f")) else: - internalError(n.info, "genLiteral(" & $n.kind & ')') + internalError(p.config, n.info, "genLiteral(" & $n.kind & ')') result = nil proc genLiteral(p: BProc, n: PNode): Rope = @@ -145,7 +145,7 @@ proc getStorageLoc(n: PNode): TStorageLoc = of tyVar, tyLent: result = OnUnknown of tyPtr: result = OnStack of tyRef: result = OnHeap - else: internalError(n.info, "getStorageLoc") + else: doAssert(false, "getStorageLoc") of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv: result = getStorageLoc(n.sons[0]) else: result = OnUnknown @@ -164,7 +164,7 @@ proc canMove(n: PNode): bool = # result = false proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = - if dest.storage == OnStack or not usesNativeGC(): + if dest.storage == OnStack or not usesNativeGC(p.config): linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) elif dest.storage == OnHeap: # location is on heap @@ -256,7 +256,7 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # (for objects, etc.): if needToCopy notin flags or tfShallow in skipTypes(dest.t, abstractVarRange).flags: - if dest.storage == OnStack or not usesNativeGC(): + if dest.storage == OnStack or not usesNativeGC(p.config): useStringh(p.module) linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", @@ -290,7 +290,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode): genRefAssign(p, dest, src, flags) else: - if dest.storage == OnStack or not usesNativeGC(): + if dest.storage == OnStack or not usesNativeGC(p.config): linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc) elif dest.storage == OnHeap: # we use a temporary to care for the dreaded self assignment: @@ -326,7 +326,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = elif needsComplexAssignment(ty): if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4: discard getTypeDesc(p.module, ty) - internalAssert ty.n != nil + internalAssert p.config, ty.n != nil genOptAsgnObject(p, dest, src, flags, ty.n, ty) else: genGenericAsgn(p, dest, src, flags) @@ -363,7 +363,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString, tyInt..tyUInt64, tyRange, tyVar, tyLent: linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) - else: internalError("genAssignment: " & $ty.kind) + else: internalError(p.config, "genAssignment: " & $ty.kind) if optMemTracker in p.options and dest.storage in {OnHeap, OnUnknown}: #writeStackTrace() @@ -409,7 +409,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = of tyPointer, tyChar, tyBool, tyEnum, tyCString, tyInt..tyUInt64, tyRange, tyVar, tyLent: linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) - else: internalError("genDeepCopy: " & $ty.kind) + else: internalError(p.config, "genDeepCopy: " & $ty.kind) proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) = if d.k != locNone: @@ -450,14 +450,14 @@ proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) = proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = var a, b: TLoc - if d.k != locNone: internalError(e.info, "binaryStmt") + if d.k != locNone: internalError(p.config, e.info, "binaryStmt") initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b)) proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = var a: TLoc - if d.k != locNone: internalError(e.info, "unaryStmt") + if d.k != locNone: internalError(p.config, e.info, "unaryStmt") initLocExpr(p, e.sons[1], a) lineCg(p, cpsStmts, frmt, [rdLoc(a)]) @@ -701,7 +701,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = of tyPtr: d.storage = OnUnknown # BUGFIX! else: - internalError(e.info, "genDeref " & $typ.kind) + internalError(p.config, e.info, "genDeref " & $typ.kind) elif p.module.compileToCpp: if typ.kind == tyVar and tfVarIsPtr notin typ.flags and e.kind == nkHiddenDeref: @@ -736,7 +736,7 @@ template inheritLocation(d: var TLoc, a: TLoc) = proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc) = initLocExpr(p, e.sons[0], a) - if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux") + if e.sons[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux") d.inheritLocation(a) discard getTypeDesc(p.module, a.t) # fill the record's fields.loc @@ -752,7 +752,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = var r = rdLoc(a) case e.sons[1].kind of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal) - else: internalError(e.info, "genTupleElem") + else: internalError(p.config, e.info, "genTupleElem") addf(r, ".Field$1", [rope(i)]) putIntoDest(p, d, e, r, a.storage) @@ -769,7 +769,7 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope; break if not p.module.compileToCpp: add(r, ".Sup") ty = ty.sons[0] - if result == nil: internalError(field.info, "genCheckedRecordField") + if result == nil: internalError(p.config, field.info, "genCheckedRecordField") proc genRecordField(p: BProc, e: PNode, d: var TLoc) = var a: TLoc @@ -786,7 +786,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = var rtyp: PType let field = lookupFieldAgain(p, ty, f, r, addr rtyp) if field.loc.r == nil and rtyp != nil: fillObjectFields(p.module, rtyp) - if field.loc.r == nil: internalError(e.info, "genRecordField 3 " & typeToString(ty)) + if field.loc.r == nil: internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty)) addf(r, ".$1", [field.loc.r]) putIntoDest(p, d, e, r, a.storage) @@ -832,7 +832,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = let field = lookupFieldAgain(p, ty, f, r) if field.loc.r == nil: fillObjectFields(p.module, ty) if field.loc.r == nil: - internalError(e.info, "genCheckedRecordField") # generate the checks: + internalError(p.config, e.info, "genCheckedRecordField") # generate the checks: genFieldCheck(p, e, r, field) add(r, rfmt(nil, ".$1", field.loc.r)) putIntoDest(p, d, e.sons[0], r, a.storage) @@ -859,7 +859,7 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = else: let idx = getOrdValue(y) if idx < firstOrd(ty) or idx > lastOrd(ty): - localError(x.info, errIndexOutOfBounds) + localError(p.config, x.info, "index out of bounds") d.inheritLocation(a) putIntoDest(p, d, n, rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage) @@ -932,7 +932,7 @@ proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) = of tySequence, tyString: genSeqElem(p, n, n.sons[0], n.sons[1], d) of tyCString: genCStringElem(p, n, n.sons[0], n.sons[1], d) of tyTuple: genTupleElem(p, n, d) - else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') + else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')') proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = # how to generate code? @@ -977,7 +977,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = proc genEcho(p: BProc, n: PNode) = # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)`` # is threadsafe. - internalAssert n.kind == nkBracket + internalAssert p.config, n.kind == nkBracket if platform.targetOS == osGenode: # bypass libc and print directly to the Genode LOG session var args: Rope = nil @@ -1003,8 +1003,8 @@ proc genEcho(p: BProc, n: PNode) = makeCString(repeat("%s", n.len) & tnl), args) linefmt(p, cpsStmts, "fflush(stdout);$n") -proc gcUsage(n: PNode) = - if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree) +proc gcUsage(conf: ConfigRef; n: PNode) = + if gSelectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree) proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = # @@ -1046,7 +1046,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = d = tmp else: genAssignment(p, d, tmp, {}) # no need for deep copying - gcUsage(e) + gcUsage(p.config, e) proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = # @@ -1083,7 +1083,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", rdLoc(dest), lens, rope(L)) add(p.s(cpsStmts), appends) - gcUsage(e) + gcUsage(p.config, e) proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq &= x --> @@ -1108,7 +1108,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p)) dest.r = rfmt(nil, "$1->data[$2]", rdLoc(a), tmpL.r) genAssignment(p, dest, b, {needToCopy, afDestIsNil}) - gcUsage(e) + gcUsage(p.config, e) proc genReset(p: BProc, n: PNode) = var a: TLoc @@ -1131,7 +1131,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) = let args = [getTypeDesc(p.module, typ), genTypeInfo(p.module, typ, a.lode.info), sizeExpr] - if a.storage == OnHeap and usesNativeGC(): + if a.storage == OnHeap and usesNativeGC(p.config): # use newObjRC1 as an optimization if canFormAcycle(a.t): linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc) @@ -1154,7 +1154,7 @@ proc genNew(p: BProc, e: PNode) = rawGenNew(p, a, se.rdLoc) else: rawGenNew(p, a, nil) - gcUsage(e) + gcUsage(p.config, e) proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) = let seqtype = skipTypes(dest.t, abstractVarRange) @@ -1162,7 +1162,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) = genTypeInfo(p.module, seqtype, dest.lode.info), length] var call: TLoc initLoc(call, locExpr, dest.lode, OnHeap) - if dest.storage == OnHeap and usesNativeGC(): + if dest.storage == OnHeap and usesNativeGC(p.config): if canFormAcycle(dest.t): linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc) else: @@ -1178,7 +1178,7 @@ proc genNewSeq(p: BProc, e: PNode) = initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) genNewSeqAux(p, a, b.rdLoc) - gcUsage(e) + gcUsage(p.config, e) proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = let seqtype = skipTypes(e.typ, abstractVarRange) @@ -1188,7 +1188,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = "($1)#nimNewSeqOfCap($2, $3)", [ getTypeDesc(p.module, seqtype), genTypeInfo(p.module, seqtype, e.info), a.rdLoc])) - gcUsage(e) + gcUsage(p.config, e) proc genConstExpr(p: BProc, n: PNode): Rope proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = @@ -1230,7 +1230,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = rawGenNew(p, tmp, nil) t = t.lastSon.skipTypes(abstractInst) r = "(*$1)" % [r] - gcUsage(e) + gcUsage(p.config, e) else: constructLoc(p, tmp) else: @@ -1244,7 +1244,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = tmp2.r = r let field = lookupFieldAgain(p, ty, it.sons[0].sym, tmp2.r) if field.loc.r == nil: fillObjectFields(p.module, ty) - if field.loc.r == nil: internalError(e.info, "genObjConstr") + if field.loc.r == nil: internalError(p.config, e.info, "genObjConstr") if it.len == 3 and optFieldCheck in p.options: genFieldCheck(p, it.sons[2], r, field) add(tmp2.r, ".") @@ -1283,7 +1283,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = arr.r = rfmt(nil, "$1->data[$2]", rdLoc(dest[]), intLiteral(i)) arr.storage = OnHeap # we know that sequences are on the heap expr(p, n[i], arr) - gcUsage(n) + gcUsage(p.config, n) if doesAlias: if d.k == locNone: d = tmp @@ -1313,7 +1313,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) else: var i: TLoc - getTemp(p, getSysType(tyInt), i) + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) let oldCode = p.s(cpsStmts) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", i.r, L.rope) initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap) @@ -1342,7 +1342,7 @@ proc genNewFinalize(p: BProc, e: PNode) = genAssignment(p, a, b, {}) # set the object type: bt = skipTypes(refType.lastSon, abstractRange) genObjectInit(p, cpsStmts, bt, a, false) - gcUsage(e) + gcUsage(p.config, e) proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope = # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we @@ -1380,7 +1380,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = add(r, ~".Sup") t = skipTypes(t.sons[0], skipPtrs) if isObjLackingTypeField(t): - globalError(x.info, errGenerated, + globalError(p.config, x.info, "no 'of' operator available for pure objects") if nilCheck != nil: r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info)) @@ -1425,7 +1425,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = of tyArray: putIntoDest(p, b, e, "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.storage) - else: internalError(e.sons[0].info, "genRepr()") + else: internalError(p.config, e.sons[0].info, "genRepr()") putIntoDest(p, d, e, ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), genTypeInfo(p.module, elemType(t), e.info)]), a.storage) @@ -1434,12 +1434,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = ropecg(p.module, "#reprAny($1, $2)", [ rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) of tyEmpty, tyVoid: - localError(e.info, "'repr' doesn't support 'void' type") + localError(p.config, e.info, "'repr' doesn't support 'void' type") else: putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", [addrLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) - gcUsage(e) + gcUsage(p.config, e) proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = let t = e.sons[1].typ @@ -1451,7 +1451,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = a.r = ropecg(p.module, frmt, [rdLoc(a)]) if d.k == locNone: getTemp(p, n.typ, d) genAssignment(p, d, a, {}) - gcUsage(n) + gcUsage(p.config, n) proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = var a = e.sons[1] @@ -1493,7 +1493,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = # YYY: length(sideeffect) is optimized away incorrectly? if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(typ))) else: putIntoDest(p, d, e, rope(lengthOrd(typ))) - else: internalError(e.info, "genArrayLen()") + else: internalError(p.config, e.info, "genArrayLen()") proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = var a, b: TLoc @@ -1511,11 +1511,11 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = lineCg(p, cpsStmts, setLenPattern, [ rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) - gcUsage(e) + gcUsage(p.config, e) proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n") - gcUsage(e) + gcUsage(p.config, e) proc genSwap(p: BProc, e: PNode, d: var TLoc) = # swap(a, b) --> @@ -1541,7 +1541,7 @@ proc rdSetElemLoc(a: TLoc, setType: PType): Rope = proc fewCmps(s: PNode): bool = # this function estimates whether it is better to emit code # for constructing the set or generating a bunch of comparisons directly - if s.kind != nkCurly: internalError(s.info, "fewCmps") + if s.kind != nkCurly: return false if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags): result = false # it is better to emit the set generation code elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}: @@ -1637,17 +1637,17 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mSymDiffSet: binaryExpr(p, e, d, "($1 ^ $2)") of mInSet: genInOp(p, e, d) - else: internalError(e.info, "genSetOp()") + else: internalError(p.config, e.info, "genSetOp()") else: case op of mIncl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] |=(1U<<($2&7U));$n") of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n") of mCard: unaryExprChar(p, e, d, "#cardSet($1, " & $size & ')') of mLtSet, mLeSet: - getTemp(p, getSysType(tyInt), i) # our counter + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) - if d.k == locNone: getTemp(p, getSysType(tyBool), d) + if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyBool), d) lineF(p, cpsStmts, lookupOpr[op], [rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)]) of mEqSet: @@ -1655,7 +1655,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)") of mMulSet, mPlusSet, mMinusSet, mSymDiffSet: # we inline the simple for loop for better code generation: - getTemp(p, getSysType(tyInt), i) # our counter + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) if d.k == locNone: getTemp(p, a.t, d) @@ -1665,7 +1665,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b), rope(lookupOpr[op])]) of mInSet: genInOp(p, e, d) - else: internalError(e.info, "genSetOp") + else: internalError(p.config, e.info, "genSetOp") proc genOrd(p: BProc, e: PNode, d: var TLoc) = unaryExprChar(p, e, d, "$1") @@ -1753,7 +1753,7 @@ proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = putIntoDest(p, d, n, ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), a.storage) - gcUsage(n) + gcUsage(p.config, n) proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = var x: TLoc @@ -1887,12 +1887,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mEcho: genEcho(p, e[1].skipConv) of mArrToSeq: genArrToSeq(p, e, d) of mNLen..mNError, mSlurp..mQuoteAst: - localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s) + localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e.sons[0].sym.name.s)) of mSpawn: - let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil) + let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil) expr(p, n, d) of mParallel: - let n = semparallel.liftParallel(p.module.module, e) + let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e) expr(p, n, d) of mDeepCopy: var a, b: TLoc @@ -1904,7 +1904,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: when defined(debugMagics): echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind - internalError(e.info, "genMagicExpr: " & $op) + internalError(p.config, e.info, "genMagicExpr: " & $op) proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = # example: { a..b, c, d, e, f..g } @@ -1924,7 +1924,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = [rdLoc(d), getTypeDesc(p.module, e.typ)]) for it in e.sons: if it.kind == nkRange: - getTemp(p, getSysType(tyInt), idx) # our counter + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter initLocExpr(p, it.sons[0], a) initLocExpr(p, it.sons[1], b) lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & @@ -1940,7 +1940,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)]) for it in e.sons: if it.kind == nkRange: - getTemp(p, getSysType(tyInt), idx) # our counter + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter initLocExpr(p, it.sons[0], a) initLocExpr(p, it.sons[1], b) lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & @@ -1984,7 +1984,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) = initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[1], b) if n.sons[0].skipConv.kind == nkClosure: - internalError(n.info, "closure to closure created") + internalError(p.config, n.info, "closure to closure created") # tasyncawait.nim breaks with this optimization: when false: if d.k != locNone: @@ -2146,11 +2146,11 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = #if sym.kind == skIterator: # echo renderTree(sym.getBody, {renderIds}) if sfCompileTime in sym.flags: - localError(n.info, "request to generate code for .compileTime proc: " & + localError(p.config, n.info, "request to generate code for .compileTime proc: " & sym.name.s) genProc(p.module, sym) if sym.loc.r == nil or sym.loc.lode == nil: - internalError(n.info, "expr: proc not init " & sym.name.s) + internalError(p.config, n.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) of skConst: if isSimpleConst(sym.typ): @@ -2168,10 +2168,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if sym.loc.r == nil or sym.loc.t == nil: #echo "FAILED FOR PRCO ", p.prc.name.s #echo renderTree(p.prc.ast, {renderIds}) - internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id + internalError p.config, n.info, "expr: var not init " & sym.name.s & "_" & $sym.id if sfThread in sym.flags: accessThreadLocalVar(p, sym) - if emulatedThreadVars(): + if emulatedThreadVars(p.config): putIntoDest(p, d, sym.loc.lode, "NimTV_->" & sym.loc.r) else: putLocIntoDest(p, d, sym.loc) @@ -2181,16 +2181,16 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if sym.loc.r == nil or sym.loc.t == nil: #echo "FAILED FOR PRCO ", p.prc.name.s #echo renderTree(p.prc.ast, {renderIds}) - internalError(n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id) + internalError(p.config, n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id) putLocIntoDest(p, d, sym.loc) of skParam: if sym.loc.r == nil or sym.loc.t == nil: # echo "FAILED FOR PRCO ", p.prc.name.s # debug p.prc.typ.n # echo renderTree(p.prc.ast, {renderIds}) - internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) + internalError(p.config, n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) putLocIntoDest(p, d, sym.loc) - else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol") + else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol") of nkNilLit: if not isEmptyType(n.typ): putIntoDest(p, d, n, genLiteral(p, n)) @@ -2259,7 +2259,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = var sym = n.sons[namePos].sym genProc(p.module, sym) if sym.loc.r == nil or sym.loc.lode == nil: - internalError(n.info, "expr: proc not init " & sym.name.s) + internalError(p.config, n.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) of nkClosure: genClosure(p, n, d) @@ -2267,7 +2267,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkWhileStmt: genWhileStmt(p, n) of nkVarSection, nkLetSection: genVarStmt(p, n) of nkConstSection: discard # consts generated lazily on use - of nkForStmt: internalError(n.info, "for statement not eliminated") + of nkForStmt: internalError(p.config, n.info, "for statement not eliminated") of nkCaseStmt: genCase(p, n, d) of nkReturnStmt: genReturnStmt(p, n) of nkBreakStmt: genBreakStmt(p, n) @@ -2327,7 +2327,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkState: genState(p, n) of nkGotoState: genGotoState(p, n) of nkBreakState: genBreakState(p, n) - else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind") + else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind") proc genNamedConstExpr(p: BProc, n: PNode): Rope = if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1]) @@ -2363,7 +2363,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = if mapType(t) == ctArray: result = rope"{}" else: result = rope"0" else: - globalError(info, "cannot create null element for: " & $t.kind) + globalError(p.config, info, "cannot create null element for: " & $t.kind) proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; count: var int) = case obj.kind @@ -2389,7 +2389,7 @@ proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; cou # not found, produce default value: result.add getDefaultValue(p, field.typ, cons.info) else: - localError(cons.info, "cannot create null element for: " & $obj) + localError(p.config, cons.info, "cannot create null element for: " & $obj) proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode, result: var Rope; count: var int) = var base = t.sons[0] diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim index 0bd00a6968..cfe71375e8 100644 --- a/compiler/ccgliterals.nim +++ b/compiler/ccgliterals.nim @@ -15,7 +15,7 @@ template detectVersion(field, corename) = if m.g.field == 0: - let core = getCompilerProc(m.g. corename) + let core = getCompilerProc(m.g.graph, corename) if core == nil or core.kind != skConst: m.g.field = 1 else: @@ -74,7 +74,7 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope = of 0, 1: result = genStringLiteralDataOnlyV1(m, s) of 2: result = genStringLiteralDataOnlyV2(m, s) else: - localError(info, "cannot determine how to produce code for string literal") + localError(m.config, info, "cannot determine how to produce code for string literal") proc genStringLiteralFromData(m: BModule; data: Rope; info: TLineInfo): Rope = result = ropecg(m, "((#NimStringDesc*) &$1)", @@ -88,4 +88,4 @@ proc genStringLiteral(m: BModule; n: PNode): Rope = of 0, 1: result = genStringLiteralV1(m, n) of 2: result = genStringLiteralV2(m, n) else: - localError(n.info, "cannot determine how to produce code for string literal") + localError(m.config, n.info, "cannot determine how to produce code for string literal") diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index cb3d6dbe6e..0ba85488b4 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -43,13 +43,13 @@ proc inExceptBlockLen(p: BProc): int = proc genVarTuple(p: BProc, n: PNode) = var tup, field: TLoc - if n.kind != nkVarTuple: internalError(n.info, "genVarTuple") + if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple") var L = sonsLen(n) # if we have a something that's been captured, use the lowering instead: for i in countup(0, L-3): if n[i].kind != nkSym: - genStmts(p, lowerTupleUnpacking(n, p.prc)) + genStmts(p, lowerTupleUnpacking(p.module.g.graph, n, p.prc)) return genLineDir(p, n) @@ -70,7 +70,7 @@ proc genVarTuple(p: BProc, n: PNode) = if t.kind == tyTuple: field.r = "$1.Field$2" % [rdLoc(tup), rope(i)] else: - if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple") + if t.n.sons[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple") field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)] putLocIntoDest(p, v.loc, field) @@ -149,7 +149,7 @@ template preserveBreakIdx(body: untyped): untyped = p.breakIdx = oldBreakIdx proc genState(p: BProc, n: PNode) = - internalAssert n.len == 1 + internalAssert p.config, n.len == 1 let n0 = n[0] if n0.kind == nkIntLit: let idx = n.sons[0].intVal @@ -191,7 +191,7 @@ proc genBreakState(p: BProc, n: PNode) = proc genGotoVar(p: BProc; value: PNode) = if value.kind notin {nkCharLit..nkUInt64Lit}: - localError(value.info, "'goto' target must be a literal value") + localError(p.config, value.info, "'goto' target must be a literal value") else: lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope]) @@ -325,7 +325,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = startBlock(p) expr(p, it.sons[0], d) endBlock(p) - else: internalError(n.info, "genIf()") + else: internalError(p.config, n.info, "genIf()") if sonsLen(n) > 1: fixLabel(p, lend) @@ -383,7 +383,7 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) = let it = caseStmt.sons[i] for j in 0 .. it.len-2: if it.sons[j].kind == nkRange: - localError(it.info, "range notation not available for computed goto") + localError(p.config, it.info, "range notation not available for computed goto") return let val = getOrdValue(it.sons[j]) lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope]) @@ -398,19 +398,19 @@ proc genComputedGoto(p: BProc; n: PNode) = let it = n.sons[i] if it.kind == nkCaseStmt: if lastSon(it).kind != nkOfBranch: - localError(it.info, + localError(p.config, it.info, "case statement must be exhaustive for computed goto"); return casePos = i let aSize = lengthOrd(it.sons[0].typ) if aSize > 10_000: - localError(it.info, + localError(p.config, it.info, "case statement has too many cases for computed goto"); return arraySize = aSize.int if firstOrd(it.sons[0].typ) != 0: - localError(it.info, + localError(p.config, it.info, "case statement has to start at 0 for computed goto"); return if casePos < 0: - localError(n.info, "no case statement found for computed goto"); return + localError(p.config, n.info, "no case statement found for computed goto"); return var id = p.labels+1 inc p.labels, arraySize+1 let tmp = "TMP$1_" % [id.rope] @@ -444,7 +444,7 @@ proc genComputedGoto(p: BProc; n: PNode) = let it = caseStmt.sons[i] for j in 0 .. it.len-2: if it.sons[j].kind == nkRange: - localError(it.info, "range notation not available for computed goto") + localError(p.config, it.info, "range notation not available for computed goto") return let val = getOrdValue(it.sons[j]) lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)]) @@ -548,7 +548,7 @@ proc genBreakStmt(p: BProc, t: PNode) = # an unnamed 'break' can only break a loop after 'transf' pass: while idx >= 0 and not p.blocks[idx].isLoop: dec idx if idx < 0 or not p.blocks[idx].isLoop: - internalError(t.info, "no loop to break") + internalError(p.config, t.info, "no loop to break") let label = assignLabel(p.blocks[idx]) blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts, @@ -876,17 +876,14 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = p.module.includeHeader("") genLineDir(p, t) var safePoint = getTempName(p.module) - if getCompilerProc("Exception") != nil: - discard cgsym(p.module, "Exception") - else: - discard cgsym(p.module, "E_Base") + discard cgsym(p.module, "Exception") linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint) linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint) - if isDefined("nimStdSetjmp"): + if isDefined(p.config, "nimStdSetjmp"): linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) - elif isDefined("nimSigSetjmp"): + elif isDefined(p.config, "nimSigSetjmp"): linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint) - elif isDefined("nimRawSetjmp"): + elif isDefined(p.config, "nimRawSetjmp"): linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint) else: linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) @@ -1139,4 +1136,4 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = proc genStmts(p: BProc, t: PNode) = var a: TLoc expr(p, t, a) - internalAssert a.k in {locNone, locTemp, locLocalVar} + internalAssert p.config, a.k in {locNone, locTemp, locLocalVar} diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 505b69eabb..c2ffa96519 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -12,11 +12,11 @@ # included from cgen.nim -proc emulatedThreadVars(): bool = +proc emulatedThreadVars(conf: ConfigRef): bool = result = {optThreads, optTlsEmulation} <= gGlobalOptions proc accessThreadLocalVar(p: BProc, s: PSym) = - if emulatedThreadVars() and not p.threadVarAccessed: + if emulatedThreadVars(p.config) and not p.threadVarAccessed: p.threadVarAccessed = true incl p.module.flags, usesThreadVars addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV_;$n", []) @@ -37,7 +37,7 @@ var # made to be one. proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) = - if emulatedThreadVars(): + if emulatedThreadVars(m.config): # we gather all thread locals var into a struct; we need to allocate # storage for that somehow, can't use the thread local storage # allocator for it :-( diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 1bb2ba98d2..0e211e2390 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -29,12 +29,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode; for i in countup(0, sonsLen(n) - 1): genTraverseProc(c, accessor, n.sons[i], typ) of nkRecCase: - if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc") + if (n.sons[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc") var p = c.p let disc = n.sons[0].sym if disc.loc.r == nil: fillObjectFields(c.p.module, typ) if disc.loc.t == nil: - internalError(n.info, "genTraverseProc()") + internalError(c.p.config, n.info, "genTraverseProc()") lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r]) for i in countup(1, sonsLen(n) - 1): let branch = n.sons[i] @@ -51,9 +51,9 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode; if field.typ.kind == tyVoid: return if field.loc.r == nil: fillObjectFields(c.p.module, typ) if field.loc.t == nil: - internalError(n.info, "genTraverseProc()") + internalError(c.p.config, n.info, "genTraverseProc()") genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t) - else: internalError(n.info, "genTraverseProc()") + else: internalError(c.p.config, n.info, "genTraverseProc()") proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} = if not m.compileToCpp: @@ -72,7 +72,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = of tyArray: let arraySize = lengthOrd(typ.sons[0]) var i: TLoc - getTemp(p, getSysType(tyInt), i) + getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i) let oldCode = p.s(cpsStmts) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", i.r, arraySize.rope) @@ -105,7 +105,7 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) = var p = c.p assert typ.kind == tySequence var i: TLoc - getTemp(p, getSysType(tyInt), i) + getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i) let oldCode = p.s(cpsStmts) lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n", [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")]) @@ -157,7 +157,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope = var sLoc = s.loc.r result = getTempName(m) - if sfThread in s.flags and emulatedThreadVars(): + if sfThread in s.flags and emulatedThreadVars(m.config): accessThreadLocalVar(p, s) sLoc = "NimTV_->" & sLoc diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 56fb379bdc..adebb6cd02 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -122,7 +122,7 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope = # check consistency: assert($typ.loc.r == $(typ.typeName & $sig)) result = typ.loc.r - if result == nil: internalError("getTypeName: " & $typ.kind) + if result == nil: internalError(m.config, "getTypeName: " & $typ.kind) proc mapSetType(typ: PType): TCTypeKind = case int(getSize(typ)) @@ -142,7 +142,7 @@ proc mapType(typ: PType): TCTypeKind = of tyOpenArray, tyArray, tyVarargs: result = ctArray of tyObject, tyTuple: result = ctStruct of tyUserTypeClasses: - internalAssert typ.isResolvedUserTypeClass + doAssert typ.isResolvedUserTypeClass return mapType(typ.lastSon) of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyInferred: @@ -156,7 +156,7 @@ proc mapType(typ: PType): TCTypeKind = of 2: result = ctUInt16 of 4: result = ctInt32 of 8: result = ctInt64 - else: internalError("mapType") + else: result = ctInt32 of tyRange: result = mapType(typ.sons[0]) of tyPtr, tyVar, tyLent, tyRef, tyOptAsRef: var base = skipTypes(typ.lastSon, typedescInst) @@ -183,8 +183,8 @@ proc mapType(typ: PType): TCTypeKind = result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) of tyStatic: if typ.n != nil: result = mapType(lastSon typ) - else: internalError("mapType") - else: internalError("mapType") + else: doAssert(false, "mapType") + else: doAssert(false, "mapType") proc mapReturnType(typ: PType): TCTypeKind = #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr @@ -239,7 +239,7 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope = result = tab.getOrDefault(sig) proc addAbiCheck(m: BModule, t: PType, name: Rope) = - if isDefined("checkabi"): + if isDefined(m.config, "checkabi"): addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(t))]) proc ccgIntroducedPtr(s: PSym): bool = @@ -303,7 +303,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) of tyStatic: if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ) - else: internalError("tyStatic for getSimpleTypeDesc") + else: internalError(m.config, "tyStatic for getSimpleTypeDesc") of tyGenericInst, tyAlias, tySink: result = getSimpleTypeDesc(m, lastSon typ) else: result = nil @@ -347,7 +347,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = else: pushType(m, concrete) doAssert m.forwTypeCache[sig] == result - else: internalError("getTypeForward(" & $typ.kind & ')') + else: internalError(m.config, "getTypeForward(" & $typ.kind & ')') proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = ## like getTypeDescAux but creates only a *weak* dependency. In other words @@ -389,7 +389,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, else: rettype = getTypeDescAux(m, t.sons[0], check) for i in countup(1, sonsLen(t.n) - 1): - if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams") + if t.n.sons[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams") var param = t.n.sons[i].sym if isCompileTimeOnly(param.typ): continue if params != nil: add(params, ~", ") @@ -442,7 +442,7 @@ proc mangleRecFieldName(m: BModule; field: PSym, rectype: PType): Rope = result = field.loc.r else: result = rope(mangleField(m, field.name)) - if result == nil: internalError(field.info, "mangleRecFieldName") + if result == nil: internalError(m.config, field.info, "mangleRecFieldName") proc genRecordFieldsAux(m: BModule, n: PNode, accessExpr: Rope, rectype: PType, @@ -453,7 +453,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, for i in countup(0, sonsLen(n) - 1): add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check)) of nkRecCase: - if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux") + if n.sons[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux") add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check)) let uname = rope(mangle(n.sons[0].sym.name.s) & 'U') let ae = if accessExpr != nil: "$1.$2" % [accessExpr, uname] @@ -481,7 +481,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, addf(unionBody, "#pragma pack(pop)$n", []) else: add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check)) - else: internalError("genRecordFieldsAux(record case branch)") + else: internalError(m.config, "genRecordFieldsAux(record case branch)") if unionBody != nil: addf(result, "union{$n$1} $2;$n", [unionBody, uname]) of nkSym: @@ -509,7 +509,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, # don't use fieldType here because we need the # tyGenericInst for C++ template support addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) - else: internalError(n.info, "genRecordFieldsAux()") + else: internalError(m.config, n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope = result = genRecordFieldsAux(m, typ.n, nil, typ, check) @@ -556,7 +556,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, # proper request to generate popCurrentExceptionEx not possible for 2 reasons: # generated function will be below declared Exception type and circular dependency # between Exception and popCurrentExceptionEx function - result = genProcHeader(m, magicsys.getCompilerProc("popCurrentExceptionEx")) & ";" & rnl & result + result = genProcHeader(m, magicsys.getCompilerProc(m.g.graph, "popCurrentExceptionEx")) & ";" & rnl & result hasField = true else: appcg(m, result, " {$n $1 Sup;$n", @@ -606,7 +606,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType = # Make sure the index refers to one of the generic params of the type. # XXX: we should catch this earlier and report it as a semantic error. if idx >= typ.len: - internalError "invalid apostrophe type parameter index" + doAssert false, "invalid apostrophe type parameter index" result = typ.sons[idx] for i in 1..stars: @@ -619,7 +619,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = var t = origTyp.skipTypes(irrelevantForBackend) if containsOrIncl(check, t.id): if not (isImportedCppType(origTyp) or isImportedCppType(t)): - internalError("cannot generate C type for: " & typeToString(origTyp)) + internalError(m.config, "cannot generate C type for: " & typeToString(origTyp)) # XXX: this BUG is hard to fix -> we need to introduce helper structs, # but determining when this needs to be done is hard. We should split # C type generation into an analysis and a code generation phase somehow. @@ -697,7 +697,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = of 2: addf(m.s[cfsTypes], "typedef NU16 $1;$n", [result]) of 4: addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result]) of 8: addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result]) - else: internalError(t.sym.info, "getTypeDescAux: enum") + else: internalError(m.config, t.sym.info, "getTypeDescAux: enum") when false: let owner = hashOwner(t.sym) if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner): @@ -808,7 +808,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = if typeInSlot == nil or typeInSlot.kind == tyVoid: result.add(~"void") elif typeInSlot.kind == tyStatic: - internalAssert typeInSlot.n != nil + internalAssert m.config, typeInSlot.n != nil result.add typeInSlot.n.renderTree else: result.add getTypeDescAux(m, typeInSlot, check) @@ -875,7 +875,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = tyUserTypeClass, tyUserTypeClassInst, tyInferred: result = getTypeDescAux(m, lastSon(t), check) else: - internalError("getTypeDescAux(" & $t.kind & ')') + internalError(m.config, "getTypeDescAux(" & $t.kind & ')') result = nil # fixes bug #145: excl(check, t.id) @@ -968,7 +968,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; if flags != 0: addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)]) discard cgsym(m, "TNimType") - if isDefined("nimTypeNames"): + if isDefined(m.config, "nimTypeNames"): var typename = typeToString(if origType.typeInst != nil: origType.typeInst else: origType, preferName) if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil: @@ -1000,7 +1000,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope = while lookupInRecord(objtype.n, d.name) == nil: objtype = objtype.sons[0] if objtype.sym == nil: - internalError(d.info, "anonymous obj with discriminator") + internalError(m.config, d.info, "anonymous obj with discriminator") result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)] proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope = @@ -1034,7 +1034,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; assert L > 0 if field.loc.r == nil: fillObjectFields(m, typ) if field.loc.t == nil: - internalError(n.info, "genObjectFields") + internalError(m.config, n.info, "genObjectFields") addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.name = $5;$n" & "$1.sons = &$6[0];$n" & @@ -1050,7 +1050,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; case b.kind of nkOfBranch: if sonsLen(b) < 2: - internalError(b.info, "genObjectFields; nkOfBranch broken") + internalError(m.config, b.info, "genObjectFields; nkOfBranch broken") for j in countup(0, sonsLen(b) - 2): if b.sons[j].kind == nkRange: var x = int(getOrdValue(b.sons[j].sons[0])) @@ -1064,23 +1064,23 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; of nkElse: addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(L), tmp2]) - else: internalError(n.info, "genObjectFields(nkRecCase)") + else: internalError(m.config, n.info, "genObjectFields(nkRecCase)") of nkSym: var field = n.sym if field.bitsize == 0: if field.loc.r == nil: fillObjectFields(m, typ) if field.loc.t == nil: - internalError(n.info, "genObjectFields") + internalError(m.config, n.info, "genObjectFields") addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.name = $5;$n", [expr, getTypeDesc(m, origType), field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)]) - else: internalError(n.info, "genObjectFields") + else: internalError(m.config, n.info, "genObjectFields") proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) = if typ.kind == tyObject: if incompleteType(typ): - localError(info, "request for RTTI generation for incomplete object: " & + localError(m.config, info, "request for RTTI generation for incomplete object: " & typeToString(typ)) genTypeInfoAux(m, typ, origType, name, info) else: @@ -1171,12 +1171,12 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1], info), info) -proc fakeClosureType(owner: PSym): PType = +proc fakeClosureType(m: BModule; owner: PSym): PType = # we generate the same RTTI as for a tuple[pointer, ref tuple[]] result = newType(tyTuple, owner) result.rawAddSon(newType(tyPointer, owner)) var r = newType(tyRef, owner) - let obj = createObj(owner, owner.info, final=false) + let obj = createObj(m.g.graph, owner, owner.info, final=false) r.rawAddSon(obj) result.rawAddSon(r) @@ -1227,15 +1227,15 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = genTypeInfoAuxBase(m, t, t, result, rope"0", info) of tyStatic: if t.n != nil: result = genTypeInfo(m, lastSon t, info) - else: internalError("genTypeInfo(" & $t.kind & ')') + else: internalError(m.config, "genTypeInfo(" & $t.kind & ')') of tyUserTypeClasses: - internalAssert t.isResolvedUserTypeClass + internalAssert m.config, t.isResolvedUserTypeClass return genTypeInfo(m, t.lastSon, info) of tyProc: if t.callConv != ccClosure: genTypeInfoAuxBase(m, t, t, result, rope"0", info) else: - let x = fakeClosureType(t.owner) + let x = fakeClosureType(m, t.owner) genTupleInfo(m, x, x, result, info) of tySequence, tyRef, tyOptAsRef: genTypeInfoAux(m, t, t, result, info) @@ -1253,7 +1253,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = # BUGFIX: use consistently RTTI without proper field names; otherwise # results are not deterministic! genTupleInfo(m, t, origType, result, info) - else: internalError("genTypeInfo(" & $t.kind & ')') + else: internalError(m.config, "genTypeInfo(" & $t.kind & ')') if t.deepCopy != nil: genDeepCopyProc(m, t.deepCopy, result) elif origType.deepCopy != nil: diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 48648bddea..a6080a8081 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -53,7 +53,7 @@ proc hashString*(s: string): BiggestInt = result = a var - gTypeTable: array[TTypeKind, TIdTable] + gTypeTable: array[TTypeKind, TIdTable] # XXX globals here gCanonicalTypes: array[TTypeKind, PType] proc initTypeTables() = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 78f6099ec7..81d7b747e8 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -19,6 +19,7 @@ import import strutils except `%` # collides with ropes.`%` from modulegraphs import ModuleGraph +from configuration import warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated import dynlib when not declared(dynlib.libCandidates): @@ -230,7 +231,7 @@ proc postStmtActions(p: BProc) {.inline.} = add(p.s(cpsStmts), p.module.injectStmt) proc accessThreadLocalVar(p: BProc, s: PSym) -proc emulatedThreadVars(): bool {.inline.} +proc emulatedThreadVars(conf: ConfigRef): bool {.inline.} proc genProc(m: BModule, prc: PSym) template compileToCpp(m: BModule): untyped = @@ -263,7 +264,7 @@ proc rdCharLoc(a: TLoc): Rope = proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, takeAddr: bool) = - if p.module.compileToCpp and t.isException and not isDefined("noCppExceptions"): + if p.module.compileToCpp and t.isException and not isDefined(p.config, "noCppExceptions"): # init vtable in Exception object for polymorphic exceptions includeHeader(p.module, "") linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t)) @@ -371,7 +372,7 @@ proc getIntTemp(p: BProc, result: var TLoc) = linefmt(p, cpsLocals, "NI $1;$n", result.r) result.k = locTemp result.storage = OnStack - result.lode = lodeTyp getSysType(tyInt) + result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo(), tyInt) result.flags = {} proc initGCFrame(p: BProc): Rope = @@ -549,7 +550,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = if lib.path.kind in {nkStrLit..nkTripleStrLit}: var s: TStringSeq = @[] libCandidates(lib.path.strVal, s) - rawMessage(hintDependency, lib.path.strVal) + rawMessage(m.config, hintDependency, lib.path.strVal) var loadlib: Rope = nil for i in countup(0, high(s)): inc(m.labels) @@ -573,7 +574,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n", [tmp, rdLoc(dest)]) - if lib.name == nil: internalError("loadDynamicLib") + if lib.name == nil: internalError(m.config, "loadDynamicLib") proc mangleDynLibProc(sym: PSym): Rope = if sfCompilerProc in sym.flags: @@ -604,14 +605,14 @@ proc symInDynamicLib(m: BModule, sym: PSym) = [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)] var last = lastSon(n) if last.kind == nkHiddenStdConv: last = last.sons[1] - internalAssert(last.kind == nkStrLit) + internalAssert(m.config, last.kind == nkStrLit) let idx = last.strVal if idx.len == 0: add(m.initProc.s(cpsStmts), load) elif idx.len == 1 and idx[0] in {'0'..'9'}: add(m.extensionLoaders[idx[0]], load) else: - internalError(sym.info, "wrong index: " & idx) + internalError(m.config, sym.info, "wrong index: " & idx) else: appcg(m, m.s[cfsDynLibInit], "\t$1 = ($2) #nimGetProcAddr($3, $4);$n", @@ -637,18 +638,18 @@ proc symInDynamicLibPartial(m: BModule, sym: PSym) = sym.typ.sym = nil # generate a new name proc cgsym(m: BModule, name: string): Rope = - let sym = magicsys.getCompilerProc(name) + let sym = magicsys.getCompilerProc(m.g.graph, name) if sym != nil: case sym.kind of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym) of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym) of skType: discard getTypeDesc(m, sym.typ) - else: internalError("cgsym: " & name & ": " & $sym.kind) + else: internalError(m.config, "cgsym: " & name & ": " & $sym.kind) else: # we used to exclude the system module from this check, but for DLL # generation support this sloppyness leads to hard to detect bugs, so # we're picky here for the system module too: - rawMessage(errSystemNeeds, name) + rawMessage(m.config, errGenerated, "system module needs: " & name) result = sym.loc.r proc generateHeaders(m: BModule) = @@ -685,7 +686,7 @@ proc closureSetup(p: BProc, prc: PSym) = # prc.ast[paramsPos].last contains the type we're after: var ls = lastSon(prc.ast[paramsPos]) if ls.kind != nkSym: - internalError(prc.info, "closure generation failed") + internalError(p.config, prc.info, "closure generation failed") var env = ls.sym #echo "created environment: ", env.id, " for ", prc.name.s assignLocalVar(p, ls) @@ -725,7 +726,7 @@ proc genProcAux(m: BModule, prc: PSym) = assert(prc.ast != nil) if sfPure notin prc.flags and prc.typ.sons[0] != nil: if resultPos >= prc.ast.len: - internalError(prc.info, "proc has no result symbol") + internalError(m.config, prc.info, "proc has no result symbol") let resNode = prc.ast.sons[resultPos] let res = resNode.sym # get result symbol if not isInvalidReturnType(prc.typ.sons[0]): @@ -924,7 +925,7 @@ proc addIntTypes(result: var Rope) {.inline.} = platform.CPU[targetCPU].intSize.rope]) if useNimNamespace : result.add("#define USE_NIM_NAMESPACE" & tnl) -proc getCopyright(cfile: Cfile): Rope = +proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = if optCompileOnly in gGlobalOptions: result = ("/* Generated by Nim Compiler v$1 */$N" & "/* (c) " & copyrightYear & " Andreas Rumpf */$N" & @@ -940,10 +941,10 @@ proc getCopyright(cfile: Cfile): Rope = rope(platform.OS[targetOS].name), rope(platform.CPU[targetCPU].name), rope(extccomp.CC[extccomp.cCompiler].name), - rope(getCompileCFileCmd(cfile))] + rope(getCompileCFileCmd(conf, cfile))] -proc getFileHeader(cfile: Cfile): Rope = - result = getCopyright(cfile) +proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope = + result = getCopyright(conf, cfile) addIntTypes(result) proc genFilenames(m: BModule): Rope = @@ -1079,7 +1080,7 @@ proc genMainProc(m: BModule) = inc(m.labels) appcg(m, m.s[cfsProcs], PreMainBody, [ m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit, - if emulatedThreadVars() and platform.targetOS != osStandalone: + if emulatedThreadVars(m.config) and platform.targetOS != osStandalone: ropecg(m, "\t#initThreadVarsEmulation();$N") else: "".rope, @@ -1138,11 +1139,11 @@ proc genInitCode(m: BModule) = add(prc, initGCFrame(m.initProc)) - add(prc, genSectionStart(cpsLocals)) + add(prc, genSectionStart(cpsLocals, m.config)) add(prc, m.preInitProc.s(cpsLocals)) add(prc, m.initProc.s(cpsLocals)) add(prc, m.postInitProc.s(cpsLocals)) - add(prc, genSectionEnd(cpsLocals)) + add(prc, genSectionEnd(cpsLocals, m.config)) if optStackTrace in m.initProc.options and frameDeclared notin m.flags: # BUT: the generated init code might depend on a current frame, so @@ -1154,17 +1155,17 @@ proc genInitCode(m: BModule) = else: add(prc, ~"\tTFrame FR_; FR_.len = 0;$N") - add(prc, genSectionStart(cpsInit)) + add(prc, genSectionStart(cpsInit, m.config)) add(prc, m.preInitProc.s(cpsInit)) add(prc, m.initProc.s(cpsInit)) add(prc, m.postInitProc.s(cpsInit)) - add(prc, genSectionEnd(cpsInit)) + add(prc, genSectionEnd(cpsInit, m.config)) - add(prc, genSectionStart(cpsStmts)) + add(prc, genSectionStart(cpsStmts, m.config)) add(prc, m.preInitProc.s(cpsStmts)) add(prc, m.initProc.s(cpsStmts)) add(prc, m.postInitProc.s(cpsStmts)) - add(prc, genSectionEnd(cpsStmts)) + add(prc, genSectionEnd(cpsStmts, m.config)) if optStackTrace in m.initProc.options and preventStackTrace notin m.flags: add(prc, deinitFrame(m.initProc)) add(prc, deinitGCFrame(m.initProc)) @@ -1174,9 +1175,9 @@ proc genInitCode(m: BModule) = [getDatInitName(m.module)]) for i in cfsTypeInit1..cfsDynLibInit: - add(prc, genSectionStart(i)) + add(prc, genSectionStart(i, m.config)) add(prc, m.s[i]) - add(prc, genSectionEnd(i)) + add(prc, genSectionEnd(i, m.config)) addf(prc, "}$N$N", []) # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because @@ -1191,15 +1192,15 @@ proc genInitCode(m: BModule) = add(m.s[cfsInitProc], ex) proc genModule(m: BModule, cfile: Cfile): Rope = - result = getFileHeader(cfile) + result = getFileHeader(m.config, cfile) result.add(genMergeInfo(m)) generateThreadLocalStorage(m) generateHeaders(m) for i in countup(cfsHeaders, cfsProcs): - add(result, genSectionStart(i)) + add(result, genSectionStart(i, m.config)) add(result, m.s[i]) - add(result, genSectionEnd(i)) + add(result, genSectionEnd(i, m.config)) if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim() add(result, m.s[cfsInitProc]) if useNimNamespace: result.add closeNamespaceNim() @@ -1246,7 +1247,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule = incl result.flags, preventStackTrace excl(result.preInitProc.options, optStackTrace) excl(result.postInitProc.options, optStackTrace) - let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(filename), "ndi") + let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi") else: "" open(result.ndi, ndiName) @@ -1307,18 +1308,19 @@ proc newModule(g: BModuleList; module: PSym): BModule = growCache g.modules, module.position g.modules[module.position] = result -template injectG(config) {.dirty.} = +template injectG() {.dirty.} = if graph.backend == nil: - graph.backend = newModuleList(config) + graph.backend = newModuleList(graph) let g = BModuleList(graph.backend) proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = - injectG(graph.config) + injectG() result = newModule(g, module) if optGenIndex in gGlobalOptions and g.generatedHeader == nil: - let f = if graph.config.headerFile.len > 0: graph.config.headerFile else: gProjectFull + let f = if graph.config.headerFile.len > 0: graph.config.headerFile + else: graph.config.projectFull g.generatedHeader = rawNewModule(g, module, - changeFileExt(completeCFilePath(f), hExt)) + changeFileExt(completeCFilePath(graph.config, f), hExt)) incl g.generatedHeader.flags, isHeaderFile proc writeHeader(m: BModule) = @@ -1334,9 +1336,9 @@ proc writeHeader(m: BModule) = generateThreadLocalStorage(m) for i in countup(cfsHeaders, cfsProcs): - add(result, genSectionStart(i)) + add(result, genSectionStart(i, m.config)) add(result, m.s[i]) - add(result, genSectionEnd(i)) + add(result, genSectionEnd(i, m.config)) if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim() add(result, m.s[cfsInitProc]) @@ -1352,18 +1354,19 @@ proc getCFile(m: BModule): string = if m.compileToCpp: ".cpp" elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m" else: ".c" - result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext) + result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext) proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext = - injectG(graph.config) + injectG() var m = newModule(g, module) readMergeInfo(getCFile(m), m) result = m proc myProcess(b: PPassContext, n: PNode): PNode = result = n - if b == nil or passes.skipCodegen(n): return + if b == nil: return var m = BModule(b) + if passes.skipCodegen(m.config, n): return m.initProc.options = initProcOptions(m) softRnl = if optLineDir in gOptions: noRnl else: rnl genStmts(m.initProc, n) @@ -1375,18 +1378,18 @@ proc finishModule(m: BModule) = # a ``for`` loop here var prc = m.forwardedProcs[i] if sfForward in prc.flags: - internalError(prc.info, "still forwarded: " & prc.name.s) + internalError(m.config, prc.info, "still forwarded: " & prc.name.s) genProcNoForward(m, prc) inc(i) assert(m.g.forwardedProcsCounter >= i) dec(m.g.forwardedProcsCounter, i) setLen(m.forwardedProcs, 0) -proc shouldRecompile(code: Rope, cfile: Cfile): bool = +proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = result = true if optForceFullMake notin gGlobalOptions: if not equalsFile(code, cfile.cname): - if isDefined("nimdiff"): + if isDefined(m.config, "nimdiff"): if fileExists(cfile.cname): copyFile(cfile.cname, cfile.cname & ".backup") echo "diff ", cfile.cname, ".backup ", cfile.cname @@ -1417,35 +1420,35 @@ proc writeModule(m: BModule, pending: bool) = add(m.s[cfsProcHeaders], m.g.mainModProcs) generateThreadVarsSize(m) - var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {}) + var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {}) var code = genModule(m, cf) when hasTinyCBackend: if gCmd == cmdRun: tccgen.compileCCode($code) return - if not shouldRecompile(code, cf): cf.flags = {CfileFlag.Cached} - addFileToCompile(cf) + if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached} + addFileToCompile(m.config, cf) elif pending and mergeRequired(m) and sfMainModule notin m.module.flags: - let cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {}) + let cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {}) mergeFiles(cfile, m) genInitCode(m) finishTypeDescriptions(m) var code = genModule(m, cf) writeRope(code, cfile) - addFileToCompile(cf) + addFileToCompile(m.config, cf) else: # 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: - var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {}) + var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {}) if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached} - addFileToCompile(cf) + addFileToCompile(m.config, cf) close(m.ndi) proc updateCachedModule(m: BModule) = let cfile = getCFile(m) - var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {}) + var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {}) if mergeRequired(m) and sfMainModule notin m.module.flags: mergeFiles(cfile, m) @@ -1456,12 +1459,13 @@ proc updateCachedModule(m: BModule) = writeRope(code, cfile) else: cf.flags = {CfileFlag.Cached} - addFileToCompile(cf) + addFileToCompile(m.config, cf) proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = result = n - if b == nil or passes.skipCodegen(n): return + if b == nil: return var m = BModule(b) + if passes.skipCodegen(m.config, n): return # if the module is cached, we don't regenerate the main proc # nor the dispatchers? But if the dispatchers changed? # XXX emit the dispatchers into its own .c file? @@ -1495,7 +1499,7 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) = m.updateCachedModule else: m.writeModule(pending=true) - writeMapping(g.mapping) + writeMapping(config, g.mapping) if g.generatedHeader != nil: writeHeader(g.generatedHeader) const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index b439381325..0c310dd7d4 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -14,6 +14,7 @@ import tables, ndi from msgs import TLineInfo +from modulegraphs import ModuleGraph type TLabel* = Rope # for the C generator a label is just a rope @@ -116,6 +117,7 @@ type breakpoints*: Rope # later the breakpoints are inserted into the main proc typeInfoMarker*: TypeCache config*: ConfigRef + graph*: ModuleGraph strVersion*, seqVersion*: int # version of the string/seq implementation to use TCGen = object of TPassContext # represents a C source file @@ -174,8 +176,9 @@ proc newProc*(prc: PSym, module: BModule): BProc = result.finallySafePoints = @[] result.sigConflicts = initCountTable[string]() -proc newModuleList*(config: ConfigRef): BModuleList = - BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: config) +proc newModuleList*(g: ModuleGraph): BModuleList = + BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config, + graph: g) iterator cgenModules*(g: BModuleList): BModule = for i in 0..high(g.modules): diff --git a/compiler/configuration.nim b/compiler/configuration.nim index fb28ef6750..e84579fdb9 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -179,6 +179,9 @@ const {low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit}, {low(TNoteKind)..high(TNoteKind)}] +const + errXMustBeCompileTime* = "'$1' can only be used in compile-time context" + #[ errStringLiteralExpected: "string literal expected", errIntLiteralExpected: "integer literal expected", @@ -352,6 +355,5 @@ errXhasSideEffects: "'$1' can have side effects", errWrongSymbolX:, errIllegalCaptureX: "illegal capture '$1'", errXCannotBeClosure: "'$1' cannot have 'closure' calling convention", -errXMustBeCompileTime: "'$1' can only be used in compile-time context", , ]# From 8ca5b71c6aead09fe78b31f4863d2b2c083ad075 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 13 May 2018 00:45:52 +0200 Subject: [PATCH 192/214] the remaining passes all compile again --- compiler/configuration.nim | 3 +- compiler/depends.nim | 6 +- compiler/docgen2.nim | 2 +- compiler/jsgen.nim | 155 +++++++++++++++++++------------------ compiler/jstypes.nim | 14 ++-- compiler/modules.nim | 36 +++++---- compiler/passaux.nim | 16 ++-- compiler/service.nim | 14 ++-- 8 files changed, 129 insertions(+), 117 deletions(-) diff --git a/compiler/configuration.nim b/compiler/configuration.nim index e84579fdb9..f9f0e623cb 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -181,6 +181,7 @@ const const errXMustBeCompileTime* = "'$1' can only be used in compile-time context" + errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected" #[ errStringLiteralExpected: "string literal expected", @@ -210,7 +211,7 @@ errUnknownCcompiler: "unknown C compiler: '$1'", errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found", errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found", errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found", -errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected", +, errInvalidMultipleAsgn: "multiple assignment is not allowed", errColonOrEqualsExpected: "':' or '=' expected, but found '$1'", errUndeclaredField: "undeclared field: '$1'", diff --git a/compiler/depends.nim b/compiler/depends.nim index 2b600c1dab..7324042328 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -19,6 +19,7 @@ proc generateDot*(project: string) type TGen = object of TPassContext module*: PSym + config: ConfigRef PGen = ref TGen var gDotGraph: Rope # the generated DOT file; we need a global variable @@ -33,10 +34,10 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode = case n.kind of nkImportStmt: for i in countup(0, sonsLen(n) - 1): - var imported = getModuleName(n.sons[i]) + var imported = getModuleName(g.config, n.sons[i]) addDependencyAux(g.module.name.s, imported) of nkFromStmt, nkImportExceptStmt: - var imported = getModuleName(n.sons[0]) + var imported = getModuleName(g.config, n.sons[0]) addDependencyAux(g.module.name.s, imported) of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i]) @@ -52,6 +53,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = var g: PGen new(g) g.module = module + g.config = graph.config result = g const gendependPass* = makePass(open = myOpen, process = addDotDependency) diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 118f1c7c53..c975e6cc7c 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -55,7 +55,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = var g: PGen new(g) g.module = module - var d = newDocumentor(module.filename, options.gConfigVars) + var d = newDocumentor(module.filename, graph.config) d.hasToc = true g.doc = d result = g diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 2ae3426ab4..2ec5a068d6 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -32,13 +32,15 @@ import ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options, nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables, times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils, - intsets, cgmeth, lowerings, sighashes + intsets, cgmeth, lowerings, sighashes, configuration from modulegraphs import ModuleGraph type TJSGen = object of TPassContext module: PSym + graph: ModuleGraph + config: ConfigRef sigConflicts: CountTable[SigHash] BModule = ref TJSGen @@ -94,14 +96,14 @@ type up: PProc # up the call chain; required for closure support declaredGlobals: IntSet -var indent = "\t".rope +template config*(p: PProc): ConfigRef = p.module.config proc indentLine(p: PProc, r: Rope): Rope = result = r var p = p while true: for i in countup(0, p.blocks.len - 1 + p.extraIndent): - prepend(result, indent) + prepend(result, "\t".rope) if p.up == nil or p.up.prc != p.prc.owner: break p = p.up @@ -194,7 +196,7 @@ proc mapType(typ: PType): TJSTypeKind = else: result = etyNone of tyProc: result = etyProc of tyCString: result = etyString - of tyUnused, tyOptAsRef: internalError("mapType") + of tyUnused, tyOptAsRef: doAssert(false, "mapType") proc mapType(p: PProc; typ: PType): TJSTypeKind = result = mapType(typ) @@ -286,18 +288,17 @@ proc genConstant(p: PProc, c: PSym) proc useMagic(p: PProc, name: string) = if name.len == 0: return - var s = magicsys.getCompilerProc(name) + var s = magicsys.getCompilerProc(p.module.graph, name) if s != nil: - internalAssert s.kind in {skProc, skFunc, skMethod, skConverter} + internalAssert p.config, s.kind in {skProc, skFunc, skMethod, skConverter} if not p.g.generatedSyms.containsOrIncl(s.id): let code = genProc(p, s) add(p.g.constants, code) else: - # we used to exclude the system module from this check, but for DLL - # generation support this sloppyness leads to hard to detect bugs, so - # we're picky here for the system module too: - if p.prc != nil: globalError(p.prc.info, errSystemNeeds, name) - else: rawMessage(errSystemNeeds, name) + if p.prc != nil: + globalError(p.config, p.prc.info, "system module needs: " & name) + else: + rawMessage(p.config, errGenerated, "system module needs: " & name) proc isSimpleExpr(p: PProc; n: PNode): bool = # calls all the way down --> can stay expression based @@ -547,7 +548,7 @@ proc genLineDir(p: PProc, n: PNode) = proc genWhileStmt(p: PProc, n: PNode) = var cond: TCompRes - internalAssert isEmptyType(n.typ) + internalAssert p.config, isEmptyType(n.typ) genLineDir(p, n) inc(p.unique) var length = len(p.blocks) @@ -634,7 +635,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = useMagic(p, "isObj") for j in countup(0, blen - 2): if n.sons[i].sons[j].kind != nkType: - internalError(n.info, "genTryStmt") + internalError(p.config, n.info, "genTryStmt") if orExpr != nil: add(orExpr, "||") addf(orExpr, "isObj($2lastJSError.m_type, $1)", [genTypeInfo(p, n.sons[i].sons[j].typ), dollar]) @@ -648,7 +649,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = if not generalCatchBranchExists: useMagic(p, "reraiseException") line(p, "else {" & tnl) - line(p, indent & "reraiseException();" & tnl) + line(p, "\treraiseException();" & tnl) line(p, "}" & tnl) addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar]) line(p, "} finally {" & tnl) @@ -701,7 +702,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = case e.kind of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n", [makeJSString(e.strVal, false)]) - else: internalError(e.info, "jsgen.genCaseStmt: 2") + else: internalError(p.config, e.info, "jsgen.genCaseStmt: 2") else: gen(p, e, cond) lineF(p, "case $1:$n", [cond.rdLoc]) @@ -715,7 +716,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = gen(p, it.sons[0], stmt) moveInto(p, stmt, r) lineF(p, "break;$n", []) - else: internalError(it.info, "jsgen.genCaseStmt") + else: internalError(p.config, it.info, "jsgen.genCaseStmt") lineF(p, "}$n", []) proc genBlock(p: PProc, n: PNode, r: var TCompRes) = @@ -723,7 +724,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) = let idx = len(p.blocks) if n.sons[0].kind != nkEmpty: # named block? - if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock") + if (n.sons[0].kind != nkSym): internalError(p.config, n.info, "genBlock") var sym = n.sons[0].sym sym.loc.k = locOther sym.position = idx+1 @@ -749,7 +750,7 @@ proc genBreakStmt(p: PProc, n: PNode) = idx = len(p.blocks) - 1 while idx >= 0 and not p.blocks[idx].isLoop: dec idx if idx < 0 or not p.blocks[idx].isLoop: - internalError(n.info, "no loop to break") + internalError(p.config, n.info, "no loop to break") p.blocks[idx].id = abs(p.blocks[idx].id) # label is used lineF(p, "break L$1;$n", [rope(p.blocks[idx].id)]) @@ -874,7 +875,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = elif b.typ == etyBaseIndex: lineF(p, "$# = $#;$n", [a.res, b.rdLoc]) else: - internalError(x.info, "genAsgn") + internalError(p.config, x.info, "genAsgn") else: lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) else: @@ -904,18 +905,18 @@ proc genSwap(p: PProc, n: PNode) = if mapType(p, skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex: let tmp2 = p.getTemp(false) if a.typ != etyBaseIndex or b.typ != etyBaseIndex: - internalError(n.info, "genSwap") + internalError(p.config, n.info, "genSwap") lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n", [tmp, a.address, b.address]) tmp = tmp2 lineF(p, "var $1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res]) -proc getFieldPosition(f: PNode): int = +proc getFieldPosition(p: PProc; f: PNode): int = case f.kind of nkIntLit..nkUInt64Lit: result = int(f.intVal) of nkSym: result = f.sym.position - else: internalError(f.info, "genFieldPosition") + else: internalError(p.config, f.info, "genFieldPosition") proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -923,13 +924,13 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) = let b = if n.kind == nkHiddenAddr: n.sons[0] else: n gen(p, b.sons[0], a) if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple: - r.res = makeJSString("Field" & $getFieldPosition(b.sons[1])) + r.res = makeJSString("Field" & $getFieldPosition(p, b.sons[1])) else: - if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr") + if b.sons[1].kind != nkSym: internalError(p.config, b.sons[1].info, "genFieldAddr") var f = b.sons[1].sym if f.loc.r == nil: f.loc.r = mangleName(p.module, f) r.res = makeJSString($f.loc.r) - internalAssert a.typ != etyBaseIndex + internalAssert p.config, a.typ != etyBaseIndex r.address = a.res r.kind = resExpr @@ -939,9 +940,9 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) = let otyp = skipTypes(n.sons[0].typ, abstractVarRange) if otyp.kind == tyTuple: r.res = ("$1.Field$2") % - [r.res, getFieldPosition(n.sons[1]).rope] + [r.res, getFieldPosition(p, n.sons[1]).rope] else: - if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess") + if n.sons[1].kind != nkSym: internalError(p.config, n.sons[1].info, "genFieldAccess") var f = n.sons[1].sym if f.loc.r == nil: f.loc.r = mangleName(p.module, f) r.res = "$1.$2" % [r.res, f.loc.r] @@ -951,7 +952,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) = let m = if n.kind == nkHiddenAddr: n.sons[0] else: n - internalAssert m.kind == nkCheckedFieldExpr + internalAssert p.config, m.kind == nkCheckedFieldExpr genAddr(p, m, r) # XXX proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) = @@ -965,7 +966,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = let m = if n.kind == nkHiddenAddr: n.sons[0] else: n gen(p, m.sons[0], a) gen(p, m.sons[1], b) - internalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex + internalAssert p.config, a.typ != etyBaseIndex and b.typ != etyBaseIndex r.address = a.res var typ = skipTypes(m.sons[0].typ, abstractPtrs) if typ.kind == tyArray: first = firstOrd(typ.sons[0]) @@ -987,9 +988,9 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) = genArrayAddr(p, n, r) of tyTuple: genFieldAddr(p, n, r) - else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') + else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')') r.typ = etyNone - if r.res == nil: internalError(n.info, "genArrayAccess") + if r.res == nil: internalError(p.config, n.info, "genArrayAccess") if ty.kind == tyCString: r.res = "$1.charCodeAt($2)" % [r.address, r.res] else: @@ -1009,7 +1010,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = case n.sons[0].kind of nkSym: let s = n.sons[0].sym - if s.loc.r == nil: internalError(n.info, "genAddr: 3") + if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3") case s.kind of skVar, skLet, skResult: r.kind = resExpr @@ -1031,8 +1032,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = else: # 'var openArray' for instance produces an 'addr' but this is harmless: gen(p, n.sons[0], r) - #internalError(n.info, "genAddr: 4 " & renderTree(n)) - else: internalError(n.info, "genAddr: 2") + #internalError(p.config, n.info, "genAddr: 4 " & renderTree(n)) + else: internalError(p.config, n.info, "genAddr: 2") of nkCheckedFieldExpr: genCheckedFieldAddr(p, n, r) of nkDotExpr: @@ -1051,12 +1052,12 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = genArrayAddr(p, n.sons[0], r) of tyTuple: genFieldAddr(p, n.sons[0], r) - else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') + else: internalError(p.config, n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') of nkObjDownConv: gen(p, n.sons[0], r) of nkHiddenDeref: gen(p, n.sons[0].sons[0], r) - else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind) + else: internalError(p.config, n.sons[0].info, "genAddr: " & $n.sons[0].kind) proc thisParam(p: PProc; typ: PType): PType = discard @@ -1090,7 +1091,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = case s.kind of skVar, skLet, skParam, skTemp, skResult, skForVar: if s.loc.r == nil: - internalError(n.info, "symbol has no generated name: " & s.name.s) + internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) let k = mapType(p, s.typ) if k == etyBaseIndex: r.typ = etyBaseIndex @@ -1107,7 +1108,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = of skConst: genConstant(p, s) if s.loc.r == nil: - internalError(n.info, "symbol has no generated name: " & s.name.s) + internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) r.res = s.loc.r of skProc, skFunc, skConverter, skMethod: discard mangleName(p.module, s) @@ -1124,7 +1125,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = genProcForSymIfNeeded(p, s) else: if s.loc.r == nil: - internalError(n.info, "symbol has no generated name: " & s.name.s) + internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) r.res = s.loc.r r.kind = resVal @@ -1145,7 +1146,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) = elif t == etyBaseIndex: r.res = "$1[0]" % [a.res] else: - internalError(n.info, "genDeref") + internalError(p.config, n.info, "genDeref") proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -1205,14 +1206,14 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) = # XXX look into this: let jsp = countJsParams(typ) if emitted != jsp and tfVarargs notin typ.flags: - localError(n.info, "wrong number of parameters emitted; expected: " & $jsp & + localError(p.config, n.info, "wrong number of parameters emitted; expected: " & $jsp & " but got: " & $emitted) r.kind = resExpr proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType; generated: var int; r: var TCompRes) = if i >= n.len: - globalError(n.info, "wrong importcpp pattern; expected parameter at position " & $i & + globalError(p.config, n.info, "wrong importcpp pattern; expected parameter at position " & $i & " but got only: " & $(n.len-1)) let it = n[i] var paramType: PNode = nil @@ -1266,7 +1267,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = if f.loc.r == nil: f.loc.r = mangleName(p.module, f) if sfInfixCall in f.flags: let pat = n.sons[0].sym.loc.r.data - internalAssert pat != nil + internalAssert p.config, pat != nil if pat.contains({'#', '(', '@'}): var typ = skipTypes(n.sons[0].typ, abstractInst) assert(typ.kind == tyProc) @@ -1276,7 +1277,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = gen(p, n.sons[1], r) if r.typ == etyBaseIndex: if r.address == nil: - globalError(n.info, "cannot invoke with infix syntax") + globalError(p.config, n.info, "cannot invoke with infix syntax") r.res = "$1[$2]" % [r.address, r.res] r.address = nil r.typ = etyNone @@ -1295,7 +1296,7 @@ proc genCall(p: PProc, n: PNode, r: var TCompRes) = proc genEcho(p: PProc, n: PNode, r: var TCompRes) = let n = n[1].skipConv - internalAssert n.kind == nkBracket + internalAssert p.config, n.kind == nkBracket useMagic(p, "toJSStr") # Used in rawEcho useMagic(p, "rawEcho") add(r.res, "rawEcho(") @@ -1326,7 +1327,7 @@ proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output: if output.len > 0: output.add(", ") output.addf("$#: ", [mangleName(p.module, rec.sym)]) output.add(createVar(p, rec.sym.typ, false)) - else: internalError(rec.info, "createRecordVarAux") + else: internalError(p.config, rec.info, "createRecordVarAux") proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: var Rope) = var t = typ @@ -1409,10 +1410,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = if t.n != nil: result = createVar(p, lastSon t, indirect) else: - internalError("createVar: " & $t.kind) + internalError(p.config, "createVar: " & $t.kind) result = nil else: - internalError("createVar: " & $t.kind) + internalError(p.config, "createVar: " & $t.kind) result = nil template returnType: untyped = @@ -1482,7 +1483,7 @@ proc genVarStmt(p: PProc, n: PNode) = var a = n.sons[i] if a.kind != nkCommentStmt: if a.kind == nkVarTuple: - let unpacked = lowerTupleUnpacking(a, p.prc) + let unpacked = lowerTupleUnpacking(p.module.graph, a, p.prc) genStmt(p, unpacked) else: assert(a.kind == nkIdentDefs) @@ -1519,7 +1520,7 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) = case skipTypes(n.sons[1].typ, abstractVar).kind of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n.sons[1], r) of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)") - else: internalError(n.info, "genOrd") + else: internalError(p.config, n.info, "genOrd") proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -1559,9 +1560,9 @@ proc genToArray(p: PProc; n: PNode; r: var TCompRes) = gen(p, it[1], b) r.res.add("$# => $#" % [a.rdLoc, b.rdLoc]) else: - localError(it.info, "'toArray' needs tuple constructors") + localError(p.config, it.info, "'toArray' needs tuple constructors") else: - localError(x.info, "'toArray' needs an array literal") + localError(p.config, x.info, "'toArray' needs an array literal") r.res.add(")") proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) = @@ -1604,7 +1605,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) = of tySet: genReprAux(p, n, r, "reprSet", genTypeInfo(p, t)) of tyEmpty, tyVoid: - localError(n.info, "'repr' doesn't support 'void' type") + localError(p.config, n.info, "'repr' doesn't support 'void' type") of tyPointer: genReprAux(p, n, r, "reprPointer") of tyOpenArray, tyVarargs: @@ -1736,7 +1737,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mReset: genReset(p, n) of mEcho: genEcho(p, n, r) of mNLen..mNError, mSlurp, mStaticExec: - localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s) + localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s) of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2))") of mCopyStrLast: @@ -1754,7 +1755,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = genCall(p, n, r) else: genCall(p, n, r) - #else internalError(e.info, 'genMagic: ' + magicToStr[op]); + #else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]); proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = var @@ -1810,7 +1811,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = for i in countup(1, sonsLen(n) - 1): if i > 1: add(initList, ", ") var it = n.sons[i] - internalAssert it.kind == nkExprColonExpr + internalAssert p.config, it.kind == nkExprColonExpr let val = it.sons[1] gen(p, val, a) var f = it.sons[0].sym @@ -1866,7 +1867,7 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) = gen(p, n.sons[0].sons[0], r) else: gen(p, n.sons[0], r) - if r.res == nil: internalError(n.info, "convStrToCStr") + if r.res == nil: internalError(p.config, n.info, "convStrToCStr") useMagic(p, "toJSStr") r.res = "toJSStr($1)" % [r.res] r.kind = resExpr @@ -1878,13 +1879,13 @@ proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) = gen(p, n.sons[0].sons[0], r) else: gen(p, n.sons[0], r) - if r.res == nil: internalError(n.info, "convCStrToStr") + if r.res == nil: internalError(p.config, n.info, "convCStrToStr") useMagic(p, "cstrToNimstr") r.res = "cstrToNimstr($1)" % [r.res] r.kind = resExpr proc genReturnStmt(p: PProc, n: PNode) = - if p.procDef == nil: internalError(n.info, "genReturnStmt") + if p.procDef == nil: internalError(p.config, n.info, "genReturnStmt") p.beforeRetNeeded = true if n.sons[0].kind != nkEmpty: genStmt(p, n.sons[0]) @@ -2140,7 +2141,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkVarSection, nkLetSection: genVarStmt(p, n) of nkConstSection: discard of nkForStmt, nkParForStmt: - internalError(n.info, "for statement not eliminated") + internalError(p.config, n.info, "for statement not eliminated") of nkCaseStmt: genCaseJS(p, n, r) of nkReturnStmt: genReturnStmt(p, n) of nkBreakStmt: genBreakStmt(p, n) @@ -2163,13 +2164,13 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = genSym(p, n.sons[namePos], r) r.res = nil of nkGotoState, nkState: - internalError(n.info, "first class iterators not implemented") + internalError(p.config, n.info, "first class iterators not implemented") of nkPragmaBlock: gen(p, n.lastSon, r) of nkComesFrom: discard "XXX to implement for better stack traces" - else: internalError(n.info, "gen: unknown node type: " & $n.kind) + else: internalError(p.config, n.info, "gen: unknown node type: " & $n.kind) -var globals: PGlobals +var globals: PGlobals # XXX global variable here proc newModule(module: PSym): BModule = new(result) @@ -2205,10 +2206,10 @@ proc genModule(p: PProc, n: PNode) = add(p.body, frameDestroy(p)) proc myProcess(b: PPassContext, n: PNode): PNode = - if passes.skipCodegen(n): return n result = n - var m = BModule(b) - if m.module == nil: internalError(n.info, "myProcess") + let m = BModule(b) + if passes.skipCodegen(m.config, n): return n + if m.module == nil: internalError(m.config, n.info, "myProcess") var p = newProc(globals, m, nil, m.module.options) p.unique = globals.unique genModule(p, n) @@ -2235,11 +2236,11 @@ proc getClassName(t: PType): Rope = if s.isNil or sfAnon in s.flags: s = skipTypes(t, abstractPtrs).sym if s.isNil or sfAnon in s.flags: - internalError("cannot retrieve class name") + doAssert(false, "cannot retrieve class name") if s.loc.r != nil: result = s.loc.r else: result = rope(s.name.s) -proc genClass(obj: PType; content: Rope; ext: string) = +proc genClass(conf: ConfigRef; obj: PType; content: Rope; ext: string) = let cls = getClassName(obj) let t = skipTypes(obj, abstractPtrs) let extends = if t.kind == tyObject and t.sons[0] != nil: @@ -2252,34 +2253,36 @@ proc genClass(obj: PType; content: Rope; ext: string) = "class $#$# {$n$#$n}$n") % [rope(VersionAsString), cls, extends, content] - let outfile = changeFileExt(completeCFilePath($cls), ext) + let outfile = changeFileExt(completeCFilePath(conf, $cls), ext) discard writeRopeIfNotEqual(result, outfile) proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = - if passes.skipCodegen(n): return n result = myProcess(b, n) var m = BModule(b) + if passes.skipCodegen(m.config, n): return n if sfMainModule in m.module.flags: let ext = "js" let f = if globals.classes.len == 0: toFilename(FileIndex m.module.position) else: "nimsystem" let code = wholeCode(graph, m) let outfile = - if options.outFile.len > 0: - if options.outFile.isAbsolute: options.outFile - else: getCurrentDir() / options.outFile + if m.config.outFile.len > 0: + if m.config.outFile.isAbsolute: m.config.outFile + else: getCurrentDir() / m.config.outFile else: - changeFileExt(completeCFilePath(f), ext) + changeFileExt(completeCFilePath(m.config, f), ext) discard writeRopeIfNotEqual(genHeader() & code, outfile) for obj, content in items(globals.classes): - genClass(obj, content, ext) + genClass(m.config, obj, content, ext) proc myOpenCached(graph: ModuleGraph; s: PSym, rd: PRodReader): PPassContext = - internalError("symbol files are not possible with the JS code generator") + internalError(graph.config, "symbol files are not possible with the JS code generator") result = nil proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext = var r = newModule(s) + r.graph = graph + r.config = graph.config result = r const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose) diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index f440ee7da2..f9e4246ebe 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -38,7 +38,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope = makeJSString(field.name.s)] of nkRecCase: length = sonsLen(n) - if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields") + if (n.sons[0].kind != nkSym): internalError(p.config, n.info, "genObjectFields") field = n.sons[0].sym s = genTypeInfo(p, field.typ) for i in countup(1, length - 1): @@ -47,7 +47,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope = case b.kind of nkOfBranch: if sonsLen(b) < 2: - internalError(b.info, "genObjectFields; nkOfBranch broken") + internalError(p.config, b.info, "genObjectFields; nkOfBranch broken") for j in countup(0, sonsLen(b) - 2): if u != nil: add(u, ", ") if b.sons[j].kind == nkRange: @@ -57,7 +57,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope = add(u, rope(getOrdValue(b.sons[j]))) of nkElse: u = rope(lengthOrd(field.typ)) - else: internalError(n.info, "genObjectFields(nkRecCase)") + else: internalError(p.config, n.info, "genObjectFields(nkRecCase)") if result != nil: add(result, ", " & tnl) addf(result, "[setConstr($1), $2]", [u, genObjectFields(p, typ, lastSon(b))]) @@ -65,7 +65,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope = "typ: $2, name: $4, sons: [$5]}") % [ mangleName(p.module, field), s, rope(lengthOrd(field.typ)), makeJSString(field.name.s), result] - else: internalError(n.info, "genObjectFields") + else: internalError(p.config, n.info, "genObjectFields") proc objHasTypeField(t: PType): bool {.inline.} = tfInheritable in t.flags or t.sons[0] != nil @@ -104,7 +104,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) = let length = sonsLen(typ.n) var s: Rope = nil for i in countup(0, length - 1): - if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo") + if (typ.n.sons[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo") let field = typ.n.sons[i].sym if i > 0: add(s, ", " & tnl) let extName = if field.ast == nil: field.name.s else: field.ast.strVal @@ -152,5 +152,5 @@ proc genTypeInfo(p: PProc, typ: PType): Rope = of tyTuple: genTupleInfo(p, t, result) of tyStatic: if t.n != nil: result = genTypeInfo(p, lastSon t) - else: internalError("genTypeInfo(" & $t.kind & ')') - else: internalError("genTypeInfo(" & $t.kind & ')') + else: internalError(p.config, "genTypeInfo(" & $t.kind & ')') + else: internalError(p.config, "genTypeInfo(" & $t.kind & ')') diff --git a/compiler/modules.nim b/compiler/modules.nim index 7fe2336dd3..47da90c5a0 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -11,10 +11,11 @@ import ast, astalgo, magicsys, std / sha1, rodread, msgs, cgendata, sigmatch, options, - idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod + idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod, + configuration -proc resetSystemArtifacts*() = - magicsys.resetSysTypes() +proc resetSystemArtifacts*(g: ModuleGraph) = + magicsys.resetSysTypes(g) proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = # We cannot call ``newSym`` here, because we have to circumvent the ID @@ -25,11 +26,11 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = let filename = fileIdx.toFullPath result.name = getIdent(splitFile(filename).name) if not isNimIdentifier(result.name.s): - rawMessage(errInvalidModuleName, result.name.s) + rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s) result.info = newLineInfo(fileIdx, 1, 1) let - pck = getPackageName(filename) + pck = getPackageName(graph.config, filename) pck2 = if pck.len > 0: pck else: "unknown" pack = getIdent(pck2) var packSym = graph.packageSyms.strTableGet(pack) @@ -49,7 +50,7 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym = strTableAdd(result.tab, result) # a module knows itself let existing = strTableGet(packSym.tab, result.name) if existing != nil and existing.info.fileIndex != result.info.fileIndex: - localError(result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath) + localError(graph.config, result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath) # strTableIncl() for error corrections: discard strTableIncl(packSym.tab, result) @@ -74,7 +75,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f discard result.id = getModuleId(fileIdx, toFullPath(fileIdx)) discard processModule(graph, result, - if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil, + if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil, rd, cache) #if optCaasEnabled in gGlobalOptions: # gMemCacheData[fileIdx].needsRecompile = Recompiled @@ -85,7 +86,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f initStrTable(result.tab) result.ast = nil discard processModule(graph, result, - if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil, + if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil, nil, cache) graph.markClientsDirty(fileIdx) when false: @@ -102,8 +103,9 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; #if sfSystemModule in result.flags: # localError(result.info, errAttemptToRedefine, result.name.s) # restore the notes for outer module: - gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes - else: ForeignPackageNotes + graph.config.notes = + if s.owner.id == gMainPackageId: graph.config.mainPackageNotes + else: graph.config.foreignPackageNotes proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = @@ -112,22 +114,22 @@ proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; graph.addIncludeDep(s.position.FileIndex, fileIdx) proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) = - if magicsys.systemModule == nil: - systemFileIdx = fileInfoIdx(options.libpath/"system.nim") + if graph.systemModule == nil: + systemFileIdx = fileInfoIdx(graph.config.libpath / "system.nim") discard graph.compileModule(systemFileIdx, cache, {sfSystemModule}) -proc wantMainModule* = - if gProjectFull.len == 0: +proc wantMainModule*(conf: ConfigRef) = + if conf.projectFull.len == 0: fatal(gCmdLineInfo, errCommandExpectsFilename) - gProjectMainIdx = int32 addFileExt(gProjectFull, NimExt).fileInfoIdx + conf.projectMainIdx = int32 addFileExt(conf.projectFull, NimExt).fileInfoIdx passes.gIncludeFile = includeModule passes.gImportModule = importModule proc compileProject*(graph: ModuleGraph; cache: IdentCache; projectFileIdx = InvalidFileIDX) = - wantMainModule() - let systemFileIdx = fileInfoIdx(options.libpath / "system.nim") + wantMainModule(graph.config) + let systemFileIdx = fileInfoIdx(graph.config.libpath / "system.nim") let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(gProjectMainIdx) else: projectFileIdx graph.importStack.add projectFile if projectFile == systemFileIdx: diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 2065d58932..f0d6bd44a8 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -10,22 +10,26 @@ ## implements some little helper passes import - strutils, ast, astalgo, passes, idents, msgs, options, idgen + strutils, ast, astalgo, passes, idents, msgs, options, idgen, configuration from modulegraphs import ModuleGraph +type + VerboseRef = ref object of TPassContext + config: ConfigRef + proc verboseOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext = #MessageOut('compiling ' + s.name.s); - result = nil # we don't need a context - rawMessage(hintProcessing, s.name.s) + result = VerboseRef(config: graph.config) + rawMessage(graph.config, hintProcessing, s.name.s) proc verboseProcess(context: PPassContext, n: PNode): PNode = result = n - if context != nil: internalError("logpass: context is not nil") + let v = VerboseRef(context) if gVerbosity == 3: # system.nim deactivates all hints, for verbosity:3 we want the processing # messages nonetheless, so we activate them again unconditionally: - incl(msgs.gNotes, hintProcessing) - message(n.info, hintProcessing, $idgen.gFrontendId) + incl(v.config.notes, hintProcessing) + message(v.config, n.info, hintProcessing, $idgen.gFrontendId) const verbosePass* = makePass(open = verboseOpen, process = verboseProcess) diff --git a/compiler/service.nim b/compiler/service.nim index 6ec9b90467..9b45f7bd71 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -11,7 +11,7 @@ import times, commands, options, msgs, nimconf, - extccomp, strutils, os, platform, parseopt, idents + extccomp, strutils, os, platform, parseopt, idents, configuration when useCaas: import net @@ -42,17 +42,17 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) = of cmdArgument: if processArgument(pass, p, argsCount, config): break if pass == passCmd2: - if optRun notin gGlobalOptions and config.arguments.len > 0 and options.command.normalize != "run": - rawMessage(errArgsNeedRunOption, []) + if optRun notin gGlobalOptions and config.arguments.len > 0 and config.command.normalize != "run": + rawMessage(config, errGenerated, errArgsNeedRunOption) proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; config: ConfigRef) = template execute(cmd) = curCaasCmd = cmd processCmdLine(passCmd2, cmd, config) action(cache) - gErrorCounter = 0 + config.errorCounter = 0 - let typ = getConfigVar("server.type") + let typ = getConfigVar(config, "server.type") case typ of "stdin": while true: @@ -65,9 +65,9 @@ proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; conf of "tcp", "": when useCaas: var server = newSocket() - let p = getConfigVar("server.port") + let p = getConfigVar(config, "server.port") let port = if p.len > 0: parseInt(p).Port else: 6000.Port - server.bindAddr(port, getConfigVar("server.address")) + server.bindAddr(port, getConfigVar(config, "server.address")) var inp = "".TaintedString server.listen() var stdoutSocket = newSocket() From 342e50e26c7023a8ac6829b02d27c3810cb45d05 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 13 May 2018 08:51:11 +0200 Subject: [PATCH 193/214] compiler compiles again; simple programs do work --- compiler/main.nim | 148 ++++++++++++++++++-------------------- compiler/modules.nim | 15 ++-- compiler/nim.nim | 83 ++++++++++----------- compiler/scriptconfig.nim | 64 ++++++++--------- 4 files changed, 152 insertions(+), 158 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index f23a3a88e4..b9afc6a8dc 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -16,9 +16,9 @@ import cgen, jsgen, json, nversion, platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, - modulegraphs, tables, rod + modulegraphs, tables, rod, configuration -from magicsys import systemModule, resetSysTypes +from magicsys import resetSysTypes proc rodPass = if gSymbolFiles in {enabledSf, writeOnlySf}: @@ -46,54 +46,55 @@ proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) = registerPass(gendependPass) #registerPass(cleanupPass) compileProject(graph, cache) - writeDepsFile(graph, gProjectFull) - generateDot(gProjectFull) - execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") & - ' ' & changeFileExt(gProjectFull, "dot")) + let project = graph.config.projectFull + writeDepsFile(graph, project) + generateDot(project) + execExternalProgram(graph.config, "dot -Tpng -o" & changeFileExt(project, "png") & + ' ' & changeFileExt(project, "dot")) proc commandCheck(graph: ModuleGraph; cache: IdentCache) = - msgs.gErrorMax = high(int) # do not stop after first error - defineSymbol("nimcheck") + graph.config.errorMax = high(int) # do not stop after first error + defineSymbol(graph.config.symbols, "nimcheck") semanticPasses() # use an empty backend for semantic checking only rodPass() compileProject(graph, cache) proc commandDoc2(graph: ModuleGraph; cache: IdentCache; json: bool) = - msgs.gErrorMax = high(int) # do not stop after first error + graph.config.errorMax = high(int) # do not stop after first error semanticPasses() if json: registerPass(docgen2JsonPass) else: registerPass(docgen2Pass) #registerPass(cleanupPass()) compileProject(graph, cache) - finishDoc2Pass(gProjectName) + finishDoc2Pass(graph.config.projectName) proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) = - extccomp.initVars() + let conf = graph.config + extccomp.initVars(conf) semanticPasses() registerPass(cgenPass) rodPass() #registerPass(cleanupPass()) compileProject(graph, cache) - cgenWriteModules(graph.backend, graph.config) + cgenWriteModules(graph.backend, conf) if gCmd != cmdRun: - let proj = changeFileExt(gProjectFull, "") - extccomp.callCCompiler(proj) - extccomp.writeJsonBuildInstructions(proj) + let proj = changeFileExt(conf.projectFull, "") + extccomp.callCCompiler(conf, proj) + extccomp.writeJsonBuildInstructions(conf, proj) if optGenScript in gGlobalOptions: - writeDepsFile(graph, toGeneratedFile(proj, "")) + writeDepsFile(graph, toGeneratedFile(conf, proj, "")) proc commandJsonScript(graph: ModuleGraph; cache: IdentCache) = - let proj = changeFileExt(gProjectFull, "") - extccomp.runJsonBuildInstructions(proj) + let proj = changeFileExt(graph.config.projectFull, "") + extccomp.runJsonBuildInstructions(graph.config, proj) proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) = #incl(gGlobalOptions, optSafeCode) setTarget(osJS, cpuJS) #initDefines() - defineSymbol("nimrod") # 'nimrod' is always defined - defineSymbol("ecmascript") # For backward compatibility - defineSymbol("js") + defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility + defineSymbol(graph.config.symbols, "js") semanticPasses() registerPass(JSgenPass) compileProject(graph, cache) @@ -101,19 +102,19 @@ proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) = proc interactivePasses(graph: ModuleGraph; cache: IdentCache) = #incl(gGlobalOptions, optSafeCode) #setTarget(osNimrodVM, cpuNimrodVM) - initDefines() - defineSymbol("nimscript") - when hasFFI: defineSymbol("nimffi") + initDefines(graph.config.symbols) + defineSymbol(graph.config.symbols, "nimscript") + when hasFFI: defineSymbol(graph.config.symbols, "nimffi") registerPass(verbosePass) registerPass(semPass) registerPass(evalPass) proc commandInteractive(graph: ModuleGraph; cache: IdentCache) = - msgs.gErrorMax = high(int) # do not stop after first error + graph.config.errorMax = high(int) # do not stop after first error interactivePasses(graph, cache) compileSystemModule(graph, cache) - if commandArgs.len > 0: - discard graph.compileModule(fileInfoIdx(gProjectFull), cache, {}) + if graph.config.commandArgs.len > 0: + discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), cache, {}) else: var m = graph.makeStdinModule() incl(m.flags, sfMainModule) @@ -125,7 +126,7 @@ proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache) carryPasses(graph, nodes, module, cache, evalPasses) proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) = - if systemModule == nil: + if graph.systemModule == nil: interactivePasses(graph, cache) compileSystemModule(graph, cache) let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" @@ -133,7 +134,7 @@ proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) = makeStdinModule(graph), cache) proc commandScan(cache: IdentCache, config: ConfigRef) = - var f = addFileExt(mainCommandArg(), NimExt) + var f = addFileExt(mainCommandArg(config), NimExt) var stream = llStreamOpen(f, fmRead) if stream != nil: var @@ -147,37 +148,32 @@ proc commandScan(cache: IdentCache, config: ConfigRef) = if tok.tokType == tkEof: break closeLexer(L) else: - rawMessage(errCannotOpenFile, f) + rawMessage(config, errGenerated, "cannot open file: " & f) const - SimulateCaasMemReset = false PrintRopeCacheStats = false proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = - when SimulateCaasMemReset: - gGlobalOptions.incl(optCaasEnabled) + let conf = graph.config setupModuleCache() # In "nim serve" scenario, each command must reset the registered passes clearPasses() gLastCmdTime = epochTime() - searchPaths.add(options.libpath) - when false: # gProjectFull.len != 0: - # current path is always looked first for modules - prependStr(searchPaths, gProjectPath) + conf.searchPaths.add(conf.libpath) setId(100) - case command.normalize + case conf.command.normalize of "c", "cc", "compile", "compiletoc": # compile means compileToC currently gCmd = cmdCompileToC commandCompileToC(graph, cache) of "cpp", "compiletocpp": gCmd = cmdCompileToCpp - defineSymbol("cpp") + defineSymbol(graph.config.symbols, "cpp") commandCompileToC(graph, cache) of "objc", "compiletooc": gCmd = cmdCompileToOC - defineSymbol("objc") + defineSymbol(graph.config.symbols, "objc") commandCompileToC(graph, cache) of "run": gCmd = cmdRun @@ -185,69 +181,68 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = extccomp.setCC("tcc") commandCompileToC(graph, cache) else: - rawMessage(errInvalidCommandX, command) + rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") of "js", "compiletojs": gCmd = cmdCompileToJS commandCompileToJS(graph, cache) of "doc0": - wantMainModule() + wantMainModule(conf) gCmd = cmdDoc loadConfigs(DocConfig, cache) - commandDoc() + commandDoc(conf) of "doc2", "doc": gCmd = cmdDoc loadConfigs(DocConfig, cache) - defineSymbol("nimdoc") + defineSymbol(conf.symbols, "nimdoc") commandDoc2(graph, cache, false) of "rst2html": gCmd = cmdRst2html loadConfigs(DocConfig, cache) - commandRst2Html() + commandRst2Html(conf) of "rst2tex": gCmd = cmdRst2tex loadConfigs(DocTexConfig, cache) - commandRst2TeX() + commandRst2TeX(conf) of "jsondoc0": - wantMainModule() + wantMainModule(conf) gCmd = cmdDoc loadConfigs(DocConfig, cache) - wantMainModule() - defineSymbol("nimdoc") - commandJson() + wantMainModule(conf) + defineSymbol(conf.symbols, "nimdoc") + commandJson(conf) of "jsondoc2", "jsondoc": gCmd = cmdDoc loadConfigs(DocConfig, cache) - wantMainModule() - defineSymbol("nimdoc") + wantMainModule(conf) + defineSymbol(conf.symbols, "nimdoc") commandDoc2(graph, cache, true) of "ctags": - wantMainModule() + wantMainModule(conf) gCmd = cmdDoc loadConfigs(DocConfig, cache) - wantMainModule() - defineSymbol("nimdoc") - commandTags() + defineSymbol(conf.symbols, "nimdoc") + commandTags(conf) of "buildindex": gCmd = cmdDoc loadConfigs(DocConfig, cache) - commandBuildIndex() + commandBuildIndex(conf) of "gendepend": gCmd = cmdGenDepend commandGenDepend(graph, cache) of "dump": gCmd = cmdDump - if getConfigVar("dump.format") == "json": - wantMainModule() + if getConfigVar(conf, "dump.format") == "json": + wantMainModule(conf) var definedSymbols = newJArray() - for s in definedSymbolNames(): definedSymbols.elems.add(%s) + for s in definedSymbolNames(conf.symbols): definedSymbols.elems.add(%s) var libpaths = newJArray() - for dir in searchPaths: libpaths.elems.add(%dir) + for dir in conf.searchPaths: libpaths.elems.add(%dir) var dumpdata = % [ (key: "version", val: %VersionAsString), - (key: "project_path", val: %gProjectFull), + (key: "project_path", val: %conf.projectFull), (key: "defined_symbols", val: definedSymbols), (key: "lib_paths", val: libpaths) ] @@ -256,27 +251,27 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = else: msgWriteln("-- list of currently defined symbols --", {msgStdout, msgSkipHook}) - for s in definedSymbolNames(): msgWriteln(s, {msgStdout, msgSkipHook}) + for s in definedSymbolNames(conf.symbols): msgWriteln(s, {msgStdout, msgSkipHook}) msgWriteln("-- end of list --", {msgStdout, msgSkipHook}) - for it in searchPaths: msgWriteln(it) + for it in conf.searchPaths: msgWriteln(it) of "check": gCmd = cmdCheck commandCheck(graph, cache) of "parse": gCmd = cmdParse - wantMainModule() - discard parseFile(FileIndex gProjectMainIdx, cache, graph.config) + wantMainModule(conf) + discard parseFile(FileIndex conf.projectMainIdx, cache, conf) of "scan": gCmd = cmdScan - wantMainModule() - commandScan(cache, graph.config) + wantMainModule(conf) + commandScan(cache, conf) msgWriteln("Beware: Indentation tokens depend on the parser's state!") of "secret": gCmd = cmdInteractive commandInteractive(graph, cache) of "e": - commandEval(graph, cache, mainCommandArg()) + commandEval(graph, cache, mainCommandArg(conf)) of "nop", "help": # prevent the "success" message: gCmd = cmdDump @@ -284,18 +279,18 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = gCmd = cmdJsonScript commandJsonScript(graph, cache) else: - rawMessage(errInvalidCommandX, command) + rawMessage(conf, errGenerated, "invalid command: " & conf.command) - if msgs.gErrorCounter == 0 and + if conf.errorCounter == 0 and gCmd notin {cmdInterpret, cmdRun, cmdDump}: when declared(system.getMaxMem): let usedMem = formatSize(getMaxMem()) & " peakmem" else: let usedMem = formatSize(getTotalMem()) - rawMessage(hintSuccessX, [$graph.config.linesCompiled, + rawMessage(conf, hintSuccessX, [$conf.linesCompiled, formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3), usedMem, - if condSyms.isDefined("release"): "Release Build" + if isDefined(conf, "release"): "Release Build" else: "Debug Build"]) when PrintRopeCacheStats: @@ -306,9 +301,6 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float), ffDecimal, 3) - when SimulateCaasMemReset: - resetMemory() + resetAttributes(conf) - resetAttributes() - -proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache()) +#proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache()) diff --git a/compiler/modules.nim b/compiler/modules.nim index 47da90c5a0..3da1bbbc72 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -115,22 +115,23 @@ proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) = if graph.systemModule == nil: - systemFileIdx = fileInfoIdx(graph.config.libpath / "system.nim") + systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim") discard graph.compileModule(systemFileIdx, cache, {sfSystemModule}) proc wantMainModule*(conf: ConfigRef) = if conf.projectFull.len == 0: - fatal(gCmdLineInfo, errCommandExpectsFilename) - conf.projectMainIdx = int32 addFileExt(conf.projectFull, NimExt).fileInfoIdx + fatal(conf, newLineInfo(conf, "command line", 1, 1), errGenerated, "command expects a filename") + conf.projectMainIdx = int32 fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt)) passes.gIncludeFile = includeModule passes.gImportModule = importModule proc compileProject*(graph: ModuleGraph; cache: IdentCache; projectFileIdx = InvalidFileIDX) = - wantMainModule(graph.config) - let systemFileIdx = fileInfoIdx(graph.config.libpath / "system.nim") - let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(gProjectMainIdx) else: projectFileIdx + let conf = graph.config + wantMainModule(conf) + let systemFileIdx = fileInfoIdx(conf, conf.libpath / "system.nim") + let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(conf.projectMainIdx) else: projectFileIdx graph.importStack.add projectFile if projectFile == systemFileIdx: discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule}) @@ -139,7 +140,7 @@ proc compileProject*(graph: ModuleGraph; cache: IdentCache; discard graph.compileModule(projectFile, cache, {sfMainModule}) proc makeModule*(graph: ModuleGraph; filename: string): PSym = - result = graph.newModule(fileInfoIdx filename) + result = graph.newModule(fileInfoIdx(graph.config, filename)) result.id = getID() proc makeStdinModule*(graph: ModuleGraph): PSym = graph.makeModule"stdin" diff --git a/compiler/nim.nim b/compiler/nim.nim index b39eefd650..d8402a2af6 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -21,7 +21,7 @@ when defined(i386) and defined(windows) and defined(vcc): import commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, extccomp, strutils, os, osproc, platform, main, parseopt, service, - nodejs, scriptconfig, idents, modulegraphs + nodejs, scriptconfig, idents, modulegraphs, configuration when hasTinyCBackend: import tccgen @@ -37,69 +37,70 @@ proc prependCurDir(f: string): string = else: result = f -proc handleCmdLine(cache: IdentCache; config: ConfigRef) = +proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = + condsyms.initDefines(conf.symbols) if paramCount() == 0: - writeCommandLineUsage(config.helpWritten) + writeCommandLineUsage(conf.helpWritten) else: # Process command line arguments: - processCmdLine(passCmd1, "", config) - if gProjectName == "-": - gProjectName = "stdinfile" - gProjectFull = "stdinfile" - gProjectPath = canonicalizePath getCurrentDir() - gProjectIsStdin = true - elif gProjectName != "": + processCmdLine(passCmd1, "", conf) + if conf.projectName == "-": + conf.projectName = "stdinfile" + conf.projectFull = "stdinfile" + conf.projectPath = canonicalizePath(conf, getCurrentDir()) + conf.projectIsStdin = true + elif conf.projectName != "": try: - gProjectFull = canonicalizePath(gProjectName) + conf.projectFull = canonicalizePath(conf, conf.projectName) except OSError: - gProjectFull = gProjectName - let p = splitFile(gProjectFull) + conf.projectFull = conf.projectName + let p = splitFile(conf.projectFull) let dir = if p.dir.len > 0: p.dir else: getCurrentDir() - gProjectPath = canonicalizePath dir - gProjectName = p.name + conf.projectPath = canonicalizePath(conf, dir) + conf.projectName = p.name else: - gProjectPath = canonicalizePath getCurrentDir() - loadConfigs(DefaultConfig, config) # load all config files - let scriptFile = gProjectFull.changeFileExt("nims") + conf.projectPath = canonicalizePath(conf, getCurrentDir()) + loadConfigs(DefaultConfig, conf) # load all config files + let scriptFile = conf.projectFull.changeFileExt("nims") if fileExists(scriptFile): - runNimScript(cache, scriptFile, freshDefines=false, config) + runNimScript(cache, scriptFile, freshDefines=false, conf) # 'nim foo.nims' means to just run the NimScript file and do nothing more: - if scriptFile == gProjectFull: return - elif fileExists(gProjectPath / "config.nims"): + if scriptFile == conf.projectFull: return + elif fileExists(conf.projectPath / "config.nims"): # directory wide NimScript file - runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config) + runNimScript(cache, conf.projectPath / "config.nims", freshDefines=false, conf) # now process command line arguments again, because some options in the # command line can overwite the config file's settings - extccomp.initVars() - processCmdLine(passCmd2, "", config) - if options.command == "": - rawMessage(errNoCommand, command) - mainCommand(newModuleGraph(config), cache) - if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics()) + extccomp.initVars(conf) + processCmdLine(passCmd2, "", conf) + if conf.command == "": + rawMessage(conf, errGenerated, "command missing") + mainCommand(newModuleGraph(conf), cache) + if optHints in gOptions and hintGCStats in conf.notes: echo(GC_getStatistics()) #echo(GC_getStatistics()) - if msgs.gErrorCounter == 0: + if conf.errorCounter == 0: when hasTinyCBackend: if gCmd == cmdRun: - tccgen.run(config.arguments) + tccgen.run(conf.arguments) if optRun in gGlobalOptions: if gCmd == cmdCompileToJS: var ex: string - if options.outFile.len > 0: - ex = options.outFile.prependCurDir.quoteShell + if conf.outFile.len > 0: + ex = conf.outFile.prependCurDir.quoteShell else: ex = quoteShell( - completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir)) - execExternalProgram(findNodeJs() & " " & ex & ' ' & config.arguments) + completeCFilePath(conf, changeFileExt(conf.projectFull, "js").prependCurDir)) + execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments) else: var binPath: string - if options.outFile.len > 0: + if conf.outFile.len > 0: # If the user specified an outFile path, use that directly. - binPath = options.outFile.prependCurDir + binPath = conf.outFile.prependCurDir else: # Figure out ourselves a valid binary name. - binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir + binPath = changeFileExt(conf.projectFull, ExeExt).prependCurDir var ex = quoteShell(binPath) - execExternalProgram(ex & ' ' & config.arguments) + execExternalProgram(conf, ex & ' ' & conf.arguments) when declared(GC_setMaxPause): GC_setMaxPause 2_000 @@ -107,10 +108,10 @@ when declared(GC_setMaxPause): when compileOption("gc", "v2") or compileOption("gc", "refc"): # the new correct mark&sweet collector is too slow :-/ GC_disableMarkAndSweep() -condsyms.initDefines() when not defined(selftest): - handleCmdLine(newIdentCache(), newConfigRef()) + let conf = newConfigRef() + handleCmdLine(newIdentCache(), conf) when declared(GC_setMaxPause): echo GC_getStatistics() - msgQuit(int8(msgs.gErrorCounter > 0)) + msgQuit(int8(conf.errorCounter > 0)) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 0cd5d1be21..30e5e48031 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -13,7 +13,7 @@ import ast, modules, idents, passes, passaux, condsyms, options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs, - os, times, osproc, wordrecg, strtabs, modulegraphs + os, times, osproc, wordrecg, strtabs, modulegraphs, configuration # we support 'cmpIgnoreStyle' natively for efficiency: from strutils import cmpIgnoreStyle, contains @@ -26,11 +26,12 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) = setResult(a, result) proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; - config: ConfigRef): PEvalContext = + graph: ModuleGraph): PEvalContext = # For Nimble we need to export 'setupVM'. - result = newCtx(module, cache, config) + result = newCtx(module, cache, graph) result.mode = emRepl registerAdditionalOps(result) + let conf = graph.config # captured vars: var errorMsg: string @@ -98,13 +99,13 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; cbconf thisDir: setResult(a, vthisDir) cbconf put: - options.setConfigVar(getString(a, 0), getString(a, 1)) + options.setConfigVar(conf, getString(a, 0), getString(a, 1)) cbconf get: - setResult(a, options.getConfigVar(a.getString 0)) + setResult(a, options.getConfigVar(conf, a.getString 0)) cbconf exists: - setResult(a, options.existsConfigVar(a.getString 0)) + setResult(a, options.existsConfigVar(conf, a.getString 0)) cbconf nimcacheDir: - setResult(a, options.getNimcacheDir()) + setResult(a, options.getNimcacheDir(conf)) cbconf paramStr: setResult(a, os.paramStr(int a.getInt 0)) cbconf paramCount: @@ -114,67 +115,66 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; cbconf cmpIgnoreCase: setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1)) cbconf setCommand: - options.command = a.getString 0 + conf.command = a.getString 0 let arg = a.getString 1 if arg.len > 0: - gProjectName = arg + conf.projectName = arg let path = - if gProjectName.isAbsolute: gProjectName - else: gProjectPath / gProjectName + if conf.projectName.isAbsolute: conf.projectName + else: conf.projectPath / conf.projectName try: - gProjectFull = canonicalizePath(path) + conf.projectFull = canonicalizePath(conf, path) except OSError: - gProjectFull = path + conf.projectFull = path cbconf getCommand: - setResult(a, options.command) + setResult(a, conf.command) cbconf switch: - processSwitch(a.getString 0, a.getString 1, passPP, module.info, config) + processSwitch(a.getString 0, a.getString 1, passPP, module.info, conf) cbconf hintImpl: processSpecificNote(a.getString 0, wHint, passPP, module.info, - a.getString 1, config) + a.getString 1, conf) cbconf warningImpl: processSpecificNote(a.getString 0, wWarning, passPP, module.info, - a.getString 1, config) + a.getString 1, conf) cbconf patchFile: let key = a.getString(0) & "_" & a.getString(1) var val = a.getString(2).addFileExt(NimExt) if {'$', '~'} in val: - val = pathSubs(val, vthisDir) + val = pathSubs(conf, val, vthisDir) elif not isAbsolute(val): val = vthisDir / val - gModuleOverrides[key] = val + conf.moduleOverrides[key] = val cbconf selfExe: setResult(a, os.getAppFilename()) cbconf cppDefine: - if config != nil: - options.cppDefine(config, a.getString(0)) + options.cppDefine(conf, a.getString(0)) proc runNimScript*(cache: IdentCache; scriptName: string; - freshDefines=true; config: ConfigRef) = - rawMessage(hintConf, scriptName) + freshDefines=true; conf: ConfigRef) = + rawMessage(conf, hintConf, scriptName) passes.gIncludeFile = includeModule passes.gImportModule = importModule - let graph = newModuleGraph(config) - if freshDefines: initDefines() + let graph = newModuleGraph(conf) + if freshDefines: initDefines(conf.symbols) - defineSymbol("nimscript") - defineSymbol("nimconfig") + defineSymbol(conf.symbols, "nimscript") + defineSymbol(conf.symbols, "nimconfig") registerPass(semPass) registerPass(evalPass) - searchPaths.add(options.libpath) + conf.searchPaths.add(conf.libpath) var m = graph.makeModule(scriptName) incl(m.flags, sfMainModule) - vm.globalCtx = setupVM(m, cache, scriptName, config) + vm.globalCtx = setupVM(m, cache, scriptName, graph) graph.compileSystemModule(cache) discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache) # ensure we load 'system.nim' again for the real non-config stuff! - resetSystemArtifacts() + resetSystemArtifacts(graph) vm.globalCtx = nil # do not remove the defined symbols #initDefines() - undefSymbol("nimscript") - undefSymbol("nimconfig") + undefSymbol(conf.symbols, "nimscript") + undefSymbol(conf.symbols, "nimconfig") From dc4aa47c29bbcc7453244a11bcdb09e2eb62f1f5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 13 May 2018 09:07:11 +0200 Subject: [PATCH 194/214] bootstrapping works --- compiler/commands.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index ba6bbab7d9..328dc2f02d 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -727,7 +727,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg) else: invalidCmdLineOption(conf, pass, switch, info) -template gCmdLineInfo*(): untyped = newLineInfo(FileIndex(0), 1, 1) +template gCmdLineInfo*(): untyped = newLineInfo(config, "command line", 1, 1) proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) = var cmd, arg: string From af593c2ef3abb323a60ae49e5f1bbb08ffb6262e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 9 May 2018 19:33:58 +0100 Subject: [PATCH 195/214] Better db_sqlite errors when db_sqlite not connected. --- lib/impure/db_sqlite.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index f88037e2f3..b1541c1ba1 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -126,6 +126,7 @@ proc tryExec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {. tags: [ReadDbEffect, WriteDbEffect].} = ## tries to execute the query and returns true if successful, false otherwise. + assert(not db.isNil, "Database not connected.") var q = dbFormat(query, args) var stmt: sqlite3.Pstmt if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK: @@ -144,6 +145,7 @@ proc newRow(L: int): Row = proc setupQuery(db: DbConn, query: SqlQuery, args: varargs[string]): Pstmt = + assert(not db.isNil, "Database not connected.") var q = dbFormat(query, args) if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db) @@ -267,6 +269,7 @@ proc tryInsertID*(db: DbConn, query: SqlQuery, {.tags: [WriteDbEffect], raises: [].} = ## executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. + assert(not db.isNil, "Database not connected.") var q = dbFormat(query, args) var stmt: sqlite3.Pstmt result = -1 From e4c088721a969ffafe621fecd8bb28dfa2fe9d18 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 13 May 2018 09:53:00 +0200 Subject: [PATCH 196/214] make nimsuggest compile again --- compiler/importer.nim | 2 +- compiler/lexer.nim | 10 +-- compiler/semexprs.nim | 2 +- compiler/semstmts.nim | 6 +- compiler/semtypes.nim | 2 +- compiler/suggest.nim | 18 ++--- nimsuggest/nimsuggest.nim | 146 ++++++++++++++++++++------------------ 7 files changed, 97 insertions(+), 89 deletions(-) diff --git a/compiler/importer.nim b/compiler/importer.nim index 05beb1d983..4e3aa8d101 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -152,7 +152,7 @@ proc myImportModule(c: PContext, n: PNode): PSym = message(c.config, n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s) else: message(c.config, n.info, warnDeprecated, result.name.s) - suggestSym(n.info, result, c.graph.usageSym, false) + suggestSym(c.config, n.info, result, c.graph.usageSym, false) proc impMod(c: PContext; it: PNode) = let m = myImportModule(c, it) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 7c89ee4a76..d01b8c4be8 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -274,7 +274,7 @@ template tokenEnd(tok, pos) {.dirty.} = when defined(nimsuggest): let colB = getColNumber(L, pos)+1 if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and - L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}: + L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: L.cursor = CursorPosition.InToken gTrackPos.col = colA.int16 colA = 0 @@ -285,7 +285,7 @@ template tokenEndIgnore(tok, pos) = when defined(nimsuggest): let colB = getColNumber(L, pos) if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and - L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}: + L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: gTrackPos.fileIndex = trackPosInvalidFileIdx gTrackPos.line = 0'u16 colA = 0 @@ -299,7 +299,7 @@ template tokenEndPrevious(tok, pos) = # the cursor in a string literal or comment: let colB = getColNumber(L, pos) if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and - L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}: + L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}: L.cursor = CursorPosition.BeforeToken gTrackPos = L.previousToken gTrackPosAttached = true @@ -1122,7 +1122,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = tok.tokType = tkParLe when defined(nimsuggest): if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and - tok.line == gTrackPos.line.int and gIdeCmd == ideCon: + tok.line == gTrackPos.line.int and L.config.ideCmd == ideCon: gTrackPos.col = tok.col.int16 of ')': tok.tokType = tkParRi @@ -1143,7 +1143,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = of '.': when defined(nimsuggest): if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and - tok.line == gTrackPos.line.int and gIdeCmd == ideSug: + tok.line == gTrackPos.line.int and L.config.ideCmd == ideSug: tok.tokType = tkDot L.cursor = CursorPosition.InToken gTrackPos.col = tok.col.int16 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5b5c7f80c8..5fe7a7a699 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2154,7 +2154,7 @@ proc semBlock(c: PContext, n: PNode): PNode = if sfGenSym notin labl.flags: addDecl(c, labl) n.sons[0] = newSymNode(labl, n.sons[0].info) - suggestSym(n.sons[0].info, labl, c.graph.usageSym) + suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym) styleCheckDef(labl) n.sons[1] = semExpr(c, n.sons[1]) n.typ = n.sons[1].typ diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0df3ee1c4d..0a51ccee47 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -62,7 +62,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = x.info = n.info incl(s.flags, sfUsed) n.sons[0] = x - suggestSym(x.info, s, c.graph.usageSym) + suggestSym(c.config, x.info, s, c.graph.usageSym) styleCheckUse(x.info, s) else: localError(c.config, n.info, errInvalidControlFlowX % s.name.s) @@ -203,7 +203,7 @@ proc semCase(c: PContext, n: PNode): PNode = for i in countup(1, sonsLen(n) - 1): var x = n.sons[i] when defined(nimsuggest): - if gIdeCmd == ideSug and exactEquals(gTrackPos, x.info) and caseTyp.kind == tyEnum: + if c.config.ideCmd == ideSug and exactEquals(gTrackPos, x.info) and caseTyp.kind == tyEnum: suggestEnum(c, x, caseTyp) case x.kind of nkOfBranch: @@ -365,7 +365,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = result = semIdentWithPragma(c, kind, n, {}) if result.owner.kind == skModule: incl(result.flags, sfGlobal) - suggestSym(n.info, result, c.graph.usageSym) + suggestSym(c.config, n.info, result, c.graph.usageSym) styleCheckDef(result) proc checkNilable(c: PContext; v: PSym) = diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f6d23403e4..f44d93f200 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -672,7 +672,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, else: rectype.sym for i in countup(0, sonsLen(n)-3): var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported}) - suggestSym(n.sons[i].info, f, c.graph.usageSym) + suggestSym(c.config, n.sons[i].info, f, c.graph.usageSym) f.typ = typ f.position = pos if fieldOwner != nil and diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 82b6038a43..ba70de1f74 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -342,12 +342,12 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) when defined(nimsuggest): if n.kind == nkSym and n.sym.kind == skError and suggestVersion == 0: # consider 'foo.|' where 'foo' is some not imported module. - let fullPath = findModule(n.sym.name.s, n.info.toFullPath) + let fullPath = findModule(c.config, n.sym.name.s, n.info.toFullPath) if fullPath.len == 0: # error: no known module name: typ = nil else: - let m = gImportModule(c.graph, c.module, fullpath.fileInfoIdx, c.cache) + let m = gImportModule(c.graph, c.module, fileInfoIdx(c.config, fullpath), c.cache) if m == nil: typ = nil else: for it in items(n.sym.tab): @@ -457,7 +457,7 @@ proc ensureIdx[T](x: var T, y: int) = proc ensureSeq[T](x: var seq[T]) = if x == nil: newSeq(x, 0) -proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} = +proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} = ## misnamed: should be 'symDeclared' when defined(nimsuggest): if suggestVersion == 0: @@ -466,17 +466,17 @@ proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.in else: s.addNoDup(info) - if gIdeCmd == ideUse: + if conf.ideCmd == ideUse: findUsages(info, s, usageSym) - elif gIdeCmd == ideDef: + elif conf.ideCmd == ideDef: findDefinition(info, s) - elif gIdeCmd == ideDus and s != nil: + elif conf.ideCmd == ideDus and s != nil: if isTracked(info, s.name.s.len): suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) findUsages(info, s, usageSym) - elif gIdeCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex: + elif conf.ideCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex: suggestResult(symToSuggest(s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) - elif gIdeCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and + elif conf.ideCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and isDecl: suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) @@ -499,7 +499,7 @@ proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = if sfDeprecated in s.flags: warnAboutDeprecated(conf, info, s) if sfError in s.flags: localError(conf, info, "usage of '$1' is a user-defined error" % s.name.s) when defined(nimsuggest): - suggestSym(info, s, usageSym, false) + suggestSym(conf, info, s, usageSym, false) proc useSym*(conf: ConfigRef; sym: PSym; usageSym: var PSym): PNode = result = newSymNode(sym) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index b2764e9ee0..bbb751ba6f 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -158,9 +158,10 @@ proc symFromInfo(graph: ModuleGraph; gTrackPos: TLineInfo): PSym = proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int; graph: ModuleGraph; cache: IdentCache) = + let conf = graph.config myLog("cmd: " & $cmd & ", file: " & file & ", dirtyFile: " & dirtyfile & "[" & $line & ":" & $col & "]") - gIdeCmd = cmd + conf.ideCmd = cmd if cmd == ideChk: msgs.structuredErrorHook = errorHook msgs.writelnHook = myLog @@ -170,33 +171,33 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int; if cmd == ideUse and suggestVersion != 0: graph.resetAllModules() var isKnownFile = true - let dirtyIdx = file.fileInfoIdx(isKnownFile) + let dirtyIdx = fileInfoIdx(conf, file, isKnownFile) if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile) else: msgs.setDirtyFile(dirtyIdx, nil) gTrackPos = newLineInfo(dirtyIdx, line, col) gTrackPosAttached = false - gErrorCounter = 0 + conf.errorCounter = 0 if suggestVersion == 1: graph.usageSym = nil if not isKnownFile: graph.compileProject(cache) - if suggestVersion == 0 and gIdeCmd in {ideUse, ideDus} and + if suggestVersion == 0 and conf.ideCmd in {ideUse, ideDus} and dirtyfile.len == 0: discard "no need to recompile anything" else: let modIdx = graph.parentModule(dirtyIdx) graph.markDirty dirtyIdx graph.markClientsDirty dirtyIdx - if gIdeCmd != ideMod: + if conf.ideCmd != ideMod: graph.compileProject(cache, modIdx) - if gIdeCmd in {ideUse, ideDus}: + if conf.ideCmd in {ideUse, ideDus}: let u = if suggestVersion != 1: graph.symFromInfo(gTrackPos) else: graph.usageSym if u != nil: listUsages(u) else: - localError(gTrackPos, "found no symbol at this position " & $gTrackPos) + localError(conf, gTrackPos, "found no symbol at this position " & $gTrackPos) proc executeEpc(cmd: IdeCmd, args: SexpNode; graph: ModuleGraph; cache: IdentCache) = @@ -257,7 +258,7 @@ proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = template setVerbosity(level: typed) = gVerbosity = level - gNotes = NotesVerbosity[gVerbosity] + conf.notes = NotesVerbosity[gVerbosity] proc connectToNextFreePort(server: Socket, host: string): Port = server.bindaddr(Port(0), host) @@ -349,16 +350,18 @@ proc replEpc(x: ThreadParams) {.thread.} = of "call": let uid = message[1].getNum + cmd = message[2].getSymbol args = message[3] - gIdeCmd = parseIdeCmd(message[2].getSymbol) - case gIdeCmd - of ideSug, ideCon, ideDef, ideUse, ideDus, ideOutline, ideHighlight: - setVerbosity(0) - else: discard - let cmd = $gIdeCmd & " " & args.argsToStr - myLog "MSG CMD: " & cmd - requests.send(cmd) + when false: + x.ideCmd[] = parseIdeCmd(message[2].getSymbol) + case x.ideCmd[] + of ideSug, ideCon, ideDef, ideUse, ideDus, ideOutline, ideHighlight: + setVerbosity(0) + else: discard + let fullCmd = cmd & " " & args.argsToStr + myLog "MSG CMD: " & fullCmd + requests.send(fullCmd) toEpc(client, uid) of "methods": returnEpc(client, message[1].getNum, listEpc()) @@ -375,6 +378,8 @@ proc replEpc(x: ThreadParams) {.thread.} = quit errMessage proc execCmd(cmd: string; graph: ModuleGraph; cache: IdentCache; cachedMsgs: CachedMsgs) = + let conf = graph.config + template sentinel() = # send sentinel for the input reading thread: results.send(Suggest(section: ideNone)) @@ -395,21 +400,21 @@ proc execCmd(cmd: string; graph: ModuleGraph; cache: IdentCache; cachedMsgs: Cac var opc = "" var i = parseIdent(cmd, opc, 0) case opc.normalize - of "sug": gIdeCmd = ideSug - of "con": gIdeCmd = ideCon - of "def": gIdeCmd = ideDef - of "use": gIdeCmd = ideUse - of "dus": gIdeCmd = ideDus - of "mod": gIdeCmd = ideMod - of "chk": gIdeCmd = ideChk - of "highlight": gIdeCmd = ideHighlight - of "outline": gIdeCmd = ideOutline + of "sug": conf.ideCmd = ideSug + of "con": conf.ideCmd = ideCon + of "def": conf.ideCmd = ideDef + of "use": conf.ideCmd = ideUse + of "dus": conf.ideCmd = ideDus + of "mod": conf.ideCmd = ideMod + of "chk": conf.ideCmd = ideChk + of "highlight": conf.ideCmd = ideHighlight + of "outline": conf.ideCmd = ideOutline of "quit": sentinel() quit() of "debug": toggle optIdeDebug of "terse": toggle optIdeTerse - of "known": gIdeCmd = ideKnown + of "known": conf.ideCmd = ideKnown else: err() var dirtyfile = "" var orig = "" @@ -423,17 +428,17 @@ proc execCmd(cmd: string; graph: ModuleGraph; cache: IdentCache; cachedMsgs: Cac i += skipWhile(cmd, seps, i) i += parseInt(cmd, col, i) - if gIdeCmd == ideKnown: - results.send(Suggest(section: ideKnown, quality: ord(fileInfoKnown(orig)))) + if conf.ideCmd == ideKnown: + results.send(Suggest(section: ideKnown, quality: ord(fileInfoKnown(conf, orig)))) else: - if gIdeCmd == ideChk: + if conf.ideCmd == ideChk: for cm in cachedMsgs: errorHook(cm.info, cm.msg, cm.sev) - execute(gIdeCmd, orig, dirtyfile, line, col, graph, cache) + execute(conf.ideCmd, orig, dirtyfile, line, col, graph, cache) sentinel() proc recompileFullProject(graph: ModuleGraph; cache: IdentCache) = #echo "recompiling full project" - resetSystemArtifacts() + resetSystemArtifacts(graph) vm.globalCtx = nil graph.resetAllModules() GC_fullcollect() @@ -441,8 +446,9 @@ proc recompileFullProject(graph: ModuleGraph; cache: IdentCache) = #echo GC_getStatistics() proc mainThread(graph: ModuleGraph; cache: IdentCache) = + let conf = graph.config if gLogging: - for it in searchPaths: + for it in conf.searchPaths: log(it) proc wrHook(line: string) {.closure.} = @@ -468,7 +474,7 @@ proc mainThread(graph: ModuleGraph; cache: IdentCache) = idle += 1 if idle == 20 and gRefresh: # we use some nimsuggest activity to enable a lazy recompile: - gIdeCmd = ideChk + conf.ideCmd = ideChk msgs.writelnHook = proc (s: string) = discard cachedMsgs.setLen 0 msgs.structuredErrorHook = proc (info: TLineInfo; msg: string; sev: Severity) = @@ -480,20 +486,21 @@ var inputThread: Thread[ThreadParams] proc mainCommand(graph: ModuleGraph; cache: IdentCache) = + let conf = graph.config clearPasses() registerPass verbosePass registerPass semPass gCmd = cmdIdeTools incl gGlobalOptions, optCaasEnabled - wantMainModule() + wantMainModule(conf) - if not fileExists(gProjectFull): - quit "cannot find file: " & gProjectFull + if not fileExists(conf.projectFull): + quit "cannot find file: " & conf.projectFull - add(searchPaths, options.libpath) + add(conf.searchPaths, conf.libpath) # do not stop after the first error: - msgs.gErrorMax = high(int) + conf.errorMax = high(int) # do not print errors, but log them msgs.writelnHook = proc (s: string) = log(s) msgs.structuredErrorHook = nil @@ -510,15 +517,15 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) = of mtcp: createThread(inputThread, replTcp, (gPort, gAddress)) of mepc: createThread(inputThread, replEpc, (gPort, gAddress)) of mcmdsug: createThread(inputThread, replCmdline, - (gPort, "sug \"" & options.gProjectFull & "\":" & gAddress)) + (gPort, "sug \"" & conf.projectFull & "\":" & gAddress)) of mcmdcon: createThread(inputThread, replCmdline, - (gPort, "con \"" & options.gProjectFull & "\":" & gAddress)) + (gPort, "con \"" & conf.projectFull & "\":" & gAddress)) mainThread(graph, cache) joinThread(inputThread) close(requests) close(results) -proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) = +proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = var p = parseopt.initOptParser(cmd) while true: parseopt.next(p) @@ -562,66 +569,67 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) = gRefresh = true of "maxresults": suggestMaxResults = parseInt(p.val) - else: processSwitch(pass, p, config) + else: processSwitch(pass, p, conf) of cmdArgument: let a = unixToNativePath(p.key) if dirExists(a) and not fileExists(a.addFileExt("nim")): - options.gProjectName = findProjectNimFile(a) + conf.projectName = findProjectNimFile(conf, a) # don't make it worse, report the error the old way: - if options.gProjectName.len == 0: options.gProjectName = a + if conf.projectName.len == 0: conf.projectName = a else: - options.gProjectName = a + conf.projectName = a # if processArgument(pass, p, argsCount): break -proc handleCmdLine(cache: IdentCache; config: ConfigRef) = +proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = + condsyms.initDefines(conf.symbols) + defineSymbol conf.symbols, "nimsuggest" + if paramCount() == 0: stdout.writeline(Usage) else: - processCmdLine(passCmd1, "", config) + processCmdLine(passCmd1, "", conf) if gMode != mstdin: msgs.writelnHook = proc (msg: string) = discard - if gProjectName != "": + if conf.projectName != "": try: - gProjectFull = canonicalizePath(gProjectName) + conf.projectFull = canonicalizePath(conf, conf.projectName) except OSError: - gProjectFull = gProjectName - var p = splitFile(gProjectFull) - gProjectPath = canonicalizePath p.dir - gProjectName = p.name + conf.projectFull = conf.projectName + var p = splitFile(conf.projectFull) + conf.projectPath = canonicalizePath(conf, p.dir) + conf.projectName = p.name else: - gProjectPath = canonicalizePath getCurrentDir() + conf.projectPath = canonicalizePath(conf, getCurrentDir()) # Find Nim's prefix dir. let binaryPath = findExe("nim") if binaryPath == "": raise newException(IOError, "Cannot find Nim standard library: Nim compiler not in PATH") - gPrefixDir = binaryPath.splitPath().head.parentDir() - if not dirExists(gPrefixDir / "lib"): gPrefixDir = "" + conf.prefixDir = binaryPath.splitPath().head.parentDir() + if not dirExists(conf.prefixDir / "lib"): conf.prefixDir = "" #msgs.writelnHook = proc (line: string) = log(line) - myLog("START " & gProjectFull) + myLog("START " & conf.projectFull) - loadConfigs(DefaultConfig, cache, config) # load all config files + loadConfigs(DefaultConfig, cache, conf) # load all config files # now process command line arguments again, because some options in the # command line can overwite the config file's settings - options.command = "nimsuggest" - let scriptFile = gProjectFull.changeFileExt("nims") + conf.command = "nimsuggest" + let scriptFile = conf.projectFull.changeFileExt("nims") if fileExists(scriptFile): # 'nimsuggest foo.nims' means to just auto-complete the NimScript file: - if scriptFile != gProjectFull: - runNimScript(cache, scriptFile, freshDefines=false, config) - elif fileExists(gProjectPath / "config.nims"): + if scriptFile != conf.projectFull: + runNimScript(cache, scriptFile, freshDefines=false, conf) + elif fileExists(conf.projectPath / "config.nims"): # directory wide NimScript file - runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config) + runNimScript(cache, conf.projectPath / "config.nims", freshDefines=false, conf) - extccomp.initVars() - processCmdLine(passCmd2, "", config) + extccomp.initVars(conf) + processCmdLine(passCmd2, "", conf) - let graph = newModuleGraph(config) + let graph = newModuleGraph(conf) graph.suggestMode = true mainCommand(graph, cache) -condsyms.initDefines() -defineSymbol "nimsuggest" handleCmdline(newIdentCache(), newConfigRef()) From 297038f70424e2d777cf7c308a9ab48cb6f66d01 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 13 May 2018 14:19:42 +0200 Subject: [PATCH 197/214] move more globals into the config object --- compiler/ccgexprs.nim | 2 +- compiler/cgen.nim | 6 +-- compiler/extccomp.nim | 12 +++--- compiler/msgs.nim | 65 +++++++++++++++---------------- compiler/options.nim | 91 ++++++++++++++++++++++++------------------- compiler/vm.nim | 18 ++++----- 6 files changed, 101 insertions(+), 93 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a78a96c13e..dff974ddbe 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2025,7 +2025,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} = let theMacro = it[0].sym add p.s(cpsStmts), initFrameNoDebug(p, frameName, makeCString theMacro.name.s, - theMacro.info.quotedFilename, it.info.line.int) + quotedFilename(p.config, theMacro.info), it.info.line.int) else: genStmts(p, it) if n.len > 0: exprOrStmt diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 81d7b747e8..3a5d66762b 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -225,7 +225,7 @@ proc genLineDir(p: BProc, t: PNode) = (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX: if freshLineInfo(p, tt.info): linefmt(p, cpsStmts, "nimln_($1, $2);$n", - line.rope, tt.info.quotedFilename) + line.rope, quotedFilename(p.config, tt.info)) proc postStmtActions(p: BProc) {.inline.} = add(p.s(cpsStmts), p.module.injectStmt) @@ -771,7 +771,7 @@ proc genProcAux(m: BModule, prc: PSym) = if optStackTrace in prc.options: add(generatedProc, p.s(cpsLocals)) var procname = makeCString(prc.name.s) - add(generatedProc, initFrame(p, procname, prc.info.quotedFilename)) + add(generatedProc, initFrame(p, procname, quotedFilename(p.config, prc.info))) else: add(generatedProc, p.s(cpsLocals)) if optProfiler in prc.options: @@ -1151,7 +1151,7 @@ proc genInitCode(m: BModule) = incl m.flags, frameDeclared if preventStackTrace notin m.flags: var procname = makeCString(m.module.name.s) - add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename)) + add(prc, initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info))) else: add(prc, ~"\tTFrame FR_; FR_.len = 0;$N") diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index bded6b3f15..8f67a7fb69 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -380,11 +380,11 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = # use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given # for niminst support let fullSuffix = - if gCmd == cmdCompileToCpp: + if conf.cmd == cmdCompileToCpp: ".cpp" & suffix - elif gCmd == cmdCompileToOC: + elif conf.cmd == cmdCompileToOC: ".objc" & suffix - elif gCmd == cmdCompileToJS: + elif conf.cmd == cmdCompileToJS: ".js" & suffix else: suffix @@ -535,7 +535,7 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} = (platform.hostOS == osWindows) proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string = - result = if gCmd == cmdCompileToCpp and not cfile.endsWith(".c"): + result = if conf.cmd == cmdCompileToCpp and not cfile.endsWith(".c"): CC[compiler].cppCompiler else: CC[compiler].compilerExe @@ -546,7 +546,7 @@ proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe - elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler + elif gMixedMode and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler else: getCompilerExe(conf, compiler, "") proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string = @@ -610,7 +610,7 @@ proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash = getCompileCFileCmd(conf, cfile)) proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = - if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}: + if conf.cmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}: return false var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1") diff --git a/compiler/msgs.nim b/compiler/msgs.nim index d8e5a5c279..6586c9992b 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -99,8 +99,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo = result.shortName = fileName.changeFileExt("") result.quotedName = fileName.makeCString result.quotedFullName = fullPath.makeCString - if optEmbedOrigSrc in gGlobalOptions or true: - result.lines = @[] + result.lines = @[] when defined(nimpretty): if result.fullPath.len > 0: try: @@ -268,10 +267,10 @@ template toFilename*(info: TLineInfo): string = template toFullPath*(info: TLineInfo): string = info.fileIndex.toFullPath -proc toMsgFilename*(info: TLineInfo): string = +proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string = if info.fileIndex.int32 < 0: result = "???" - elif gListFullPaths: + elif optListFullPaths in conf.globalOptions: result = fileInfos[info.fileIndex.int32].fullPath else: result = fileInfos[info.fileIndex.int32].projPath @@ -306,7 +305,7 @@ type msgSkipHook ## skip message hook even if it is present MsgFlags* = set[MsgFlag] -proc msgWriteln*(s: string, flags: MsgFlags = {}) = +proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = ## Writes given message string to stderr by default. ## If ``--stdout`` option is given, writes to stdout instead. If message hook ## is present, then it is used to output message rather than stderr/stdout. @@ -318,7 +317,7 @@ proc msgWriteln*(s: string, flags: MsgFlags = {}) = if not isNil(writelnHook) and msgSkipHook notin flags: writelnHook(s) - elif optStdout in gGlobalOptions or msgStdout in flags: + elif optStdout in conf.globalOptions or msgStdout in flags: if eStdOut in errorOutputs: writeLine(stdout, s) flushFile(stdout) @@ -359,13 +358,13 @@ template callWritelnHook(args: varargs[string, `$`]) = template styledMsgWriteln*(args: varargs[typed]) = if not isNil(writelnHook): callIgnoringStyle(callWritelnHook, nil, args) - elif optStdout in gGlobalOptions: + elif optStdout in conf.globalOptions: if eStdOut in errorOutputs: callIgnoringStyle(writeLine, stdout, args) flushFile(stdout) else: if eStdErr in errorOutputs: - if optUseColors in gGlobalOptions: + if optUseColors in conf.globalOptions: callStyledWriteLineStderr(args) else: callIgnoringStyle(writeLine, stderr, args) @@ -405,14 +404,14 @@ proc quit(conf: ConfigRef; msg: TMsgKind) = proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) = if msg >= fatalMin and msg <= fatalMax: - if gCmd == cmdIdeTools: log(s) + if conf.cmd == cmdIdeTools: log(s) quit(conf, msg) if msg >= errMin and msg <= errMax: inc(conf.errorCounter) - options.gExitcode = 1'i8 + conf.exitcode = 1'i8 if conf.errorCounter >= conf.errorMax: quit(conf, msg) - elif eh == doAbort and gCmd != cmdIdeTools: + elif eh == doAbort and conf.cmd != cmdIdeTools: quit(conf, msg) elif eh == doRaise: raiseRecoverableError(s) @@ -433,7 +432,7 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) = Severity.Error) else: styledMsgWriteln(styleBright, - PosFormat % [toMsgFilename(msgContext[i]), + PosFormat % [toMsgFilename(conf, msgContext[i]), coordToStr(msgContext[i].line.int), coordToStr(msgContext[i].col+1)], resetStyle, @@ -441,7 +440,7 @@ proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) = info = msgContext[i] proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool = - msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions + msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = var @@ -457,7 +456,7 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = color = ErrorColor of warnMin..warnMax: sev = Severity.Warning - if optWarns notin gOptions: return + if optWarns notin conf.options: return if msg notin conf.notes: return writeContext(conf, unknownLineInfo()) title = WarningTitle @@ -466,7 +465,7 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint - if optHints notin gOptions: return + if optHints notin conf.options: return if msg notin conf.notes: return title = HintTitle color = HintColor @@ -489,20 +488,20 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) = rawMessage(conf, msg, [arg]) proc resetAttributes*(conf: ConfigRef) = - if {optUseColors, optStdout} * gGlobalOptions == {optUseColors}: + if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}: terminal.resetAttributes(stderr) proc writeSurroundingSrc(conf: ConfigRef; info: TLineInfo) = const indent = " " - msgWriteln(indent & $sourceLine(conf, info)) - msgWriteln(indent & spaces(info.col) & '^') + msgWriteln(conf, indent & $sourceLine(conf, info)) + msgWriteln(conf, indent & spaces(info.col) & '^') -proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string = +proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string = let title = case msg of warnMin..warnMax: WarningTitle of hintMin..hintMax: HintTitle else: ErrorTitle - result = PosFormat % [toMsgFilename(info), coordToStr(info.line.int), + result = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int), coordToStr(info.col+1)] & title & getMessageStr(msg, arg) @@ -527,7 +526,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, lastError = info of warnMin..warnMax: sev = Severity.Warning - ignoreMsg = optWarns notin gOptions or msg notin conf.notes + ignoreMsg = optWarns notin conf.options or msg notin conf.notes if not ignoreMsg: writeContext(conf, info) title = WarningTitle color = WarningColor @@ -535,7 +534,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, inc(conf.warnCounter) of hintMin..hintMax: sev = Severity.Hint - ignoreMsg = optHints notin gOptions or msg notin conf.notes + ignoreMsg = optHints notin conf.options or msg notin conf.notes title = HintTitle color = HintColor if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)] @@ -543,7 +542,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, # NOTE: currently line info line numbers start with 1, # but column numbers start with 0, however most editors expect # first column to be 1, so we need to +1 here - let x = PosFormat % [toMsgFilename(info), coordToStr(info.line.int), + let x = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int), coordToStr(info.col+1)] let s = getMessageStr(msg, arg) @@ -585,12 +584,12 @@ proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = liMessage(conf, info, msg, arg, doNothing) proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) = - if gCmd == cmdIdeTools and structuredErrorHook.isNil: return + if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return writeContext(conf, info) liMessage(conf, info, errInternal, errMsg, doAbort) proc internalError*(conf: ConfigRef; errMsg: string) = - if gCmd == cmdIdeTools and structuredErrorHook.isNil: return + if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return writeContext(conf, unknownLineInfo()) rawMessage(conf, errInternal, errMsg) @@ -619,9 +618,9 @@ proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope = result = fileInfos[i.fileIndex.int32].lines[i.line.int-1] -proc quotedFilename*(i: TLineInfo): Rope = +proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope = assert i.fileIndex.int32 >= 0 - if optExcessiveStackTrace in gGlobalOptions: + if optExcessiveStackTrace in conf.globalOptions: result = fileInfos[i.fileIndex.int32].quotedFullName else: result = fileInfos[i.fileIndex.int32].quotedName @@ -634,21 +633,21 @@ ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) = rawMessage(newPartialConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg) proc listWarnings*(conf: ConfigRef) = - msgWriteln("Warnings:") + msgWriteln(conf, "Warnings:") for warn in warnMin..warnMax: - msgWriteln(" [$1] $2" % [ + msgWriteln(conf, " [$1] $2" % [ if warn in conf.notes: "x" else: " ", configuration.WarningsToStr[ord(warn) - ord(warnMin)] ]) proc listHints*(conf: ConfigRef) = - msgWriteln("Hints:") + msgWriteln(conf, "Hints:") for hint in hintMin..hintMax: - msgWriteln(" [$1] $2" % [ + msgWriteln(conf, " [$1] $2" % [ if hint in conf.notes: "x" else: " ", configuration.HintsToStr[ord(hint) - ord(hintMin)] ]) # enable colors by default on terminals -if terminal.isatty(stderr): - incl(gGlobalOptions, optUseColors) +#if terminal.isatty(stderr): +# incl(gGlobalOptions, optUseColors) diff --git a/compiler/options.nim b/compiler/options.nim index 9d265d5031..c918cac685 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -70,6 +70,11 @@ type # please make sure we have under 32 options optIdeTerse # idetools: use terse descriptions optNoCppExceptions # use C exception handling even with CPP optExcessiveStackTrace # fully qualified module filenames + opWholeProject # for 'doc2': output any dependency + optListFullPaths + optNoNimblePath + optDynlibOverrideAll + optUseNimNamespace TGlobalOptions* = set[TGlobalOption] @@ -111,8 +116,22 @@ type destructor, notnil + SymbolFilesOption* = enum + disabledSf, enabledSf, writeOnlySf, readOnlySf, v2Sf + ConfigRef* = ref object ## eventually all global configuration should be moved here linesCompiled*: int # all lines that have been compiled + options*: TOptions + globalOptions*: TGlobalOptions + exitcode*: int8 + cmd*: TCommands # the command + selectedGC*: TGCMode # the selected GC + verbosity*: int # how verbose the compiler is + numberOfProcessors*: int # number of processors + evalExpr*: string # expression for idetools --eval + lastCmdTime*: float # when caas is enabled, we measure each command + symbolFiles*: SymbolFilesOption + cppDefines*: HashSet[string] headerFile*: string features*: set[Feature] @@ -154,6 +173,17 @@ type const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} +const + ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck, + optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck, + optMoveCheck} + + DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck, + optBoundsCheck, optOverflowCheck, optAssert, optWarns, + optHints, optStackTrace, optLineTrace, + optPatterns, optNilCheck, optMoveCheck} + DefaultGlobalOptions* = {optThreadAnalysis, optUseColors} + template newPackageCache*(): untyped = newStringTable(when FileSystemCaseSensitive: modeCaseInsensitive @@ -161,7 +191,13 @@ template newPackageCache*(): untyped = modeCaseSensitive) proc newConfigRef*(): ConfigRef = - result = ConfigRef(cppDefines: initSet[string](), + result = ConfigRef( + selectedGC: gcRefc, + verbosity: 1, + options: DefaultOptions, + globalOptions: DefaultGlobalOptions, + evalExpr: "", + cppDefines: initSet[string](), headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic, hintQuitCalled, hintExecuting}, notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], @@ -188,7 +224,12 @@ proc newConfigRef*(): ConfigRef = proc newPartialConfigRef*(): ConfigRef = ## create a new ConfigRef that is only good enough for error reporting. - result = ConfigRef(foreignPackageNotes: {hintProcessing, warnUnknownMagic, + result = ConfigRef( + selectedGC: gcRefc, + verbosity: 1, + options: DefaultOptions, + globalOptions: DefaultGlobalOptions, + foreignPackageNotes: {hintProcessing, warnUnknownMagic, hintQuitCalled, hintExecuting}, notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1]) @@ -234,48 +275,15 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = osDragonfly, osMacosx} else: discard -const - ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck, - optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck, - optMoveCheck} - -var - gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck, - optBoundsCheck, optOverflowCheck, optAssert, optWarns, - optHints, optStackTrace, optLineTrace, - optPatterns, optNilCheck, optMoveCheck} - gGlobalOptions*: TGlobalOptions = {optThreadAnalysis} - gExitcode*: int8 - gCmd*: TCommands = cmdNone # the command - gSelectedGC* = gcRefc # the selected GC - #headerFile*: string = "" - gVerbosity* = 1 # how verbose the compiler is - gNumberOfProcessors*: int # number of processors - gWholeProject*: bool # for 'doc2': output any dependency - gEvalExpr* = "" # expression for idetools --eval - gLastCmdTime*: float # when caas is enabled, we measure each command - gListFullPaths*: bool - gPreciseStack*: bool - gNoNimblePath*: bool - gDynlibOverrideAll*: bool - useNimNamespace*: bool - -type - SymbolFilesOption* = enum - disabledSf, enabledSf, writeOnlySf, readOnlySf, v2Sf - -var gSymbolFiles*: SymbolFilesOption - -proc importantComments*(conf: ConfigRef): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} -proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = gSelectedGC >= gcRefc -template preciseStack*(conf: ConfigRef): bool = gPreciseStack +proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools} +proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc template compilationCachePresent*(conf: ConfigRef): untyped = - gSymbolFiles in {enabledSf, writeOnlySf} + conf.symbolFiles in {enabledSf, writeOnlySf} # {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {} template optPreserveOrigSource*(conf: ConfigRef): untyped = - optEmbedOrigSrc in gGlobalOptions + optEmbedOrigSrc in conf.globalOptions const genSubDir* = "nimcache" @@ -374,7 +382,7 @@ proc removeTrailingDirSep*(path: string): string = result = path proc disableNimblePath*(conf: ConfigRef) = - gNoNimblePath = true + incl conf.globalOptions, optNoNimblePath conf.lazyPaths.setLen(0) include packagehandling @@ -503,7 +511,8 @@ proc inclDynlibOverride*(conf: ConfigRef; lib: string) = conf.dllOverrides[lib.canonDynlibName] = "true" proc isDynlibOverride*(conf: ConfigRef; lib: string): bool = - result = gDynlibOverrideAll or conf.dllOverrides.hasKey(lib.canonDynlibName) + result = optDynlibOverrideAll in conf.globalOptions or + conf.dllOverrides.hasKey(lib.canonDynlibName) proc binaryStrSearch*(x: openArray[string], y: string): int = var a = 0 diff --git a/compiler/vm.nim b/compiler/vm.nim index 5aa1517e4e..b001cdc074 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -61,7 +61,7 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = while x != nil: inc calls x = x.next - msgWriteln($calls & " calls omitted\n") + msgWriteln(c.config, $calls & " calls omitted\n") return stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1) var info = c.debug[pc] @@ -78,11 +78,11 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = if x.prc != nil: for k in 1..max(1, 25-s.len): add(s, ' ') add(s, x.prc.name.s) - msgWriteln(s) + msgWriteln(c.config, s) proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: string, n: PNode = nil) = - msgWriteln("stack trace: (most recent call last)") + msgWriteln(c.config, "stack trace: (most recent call last)") stackTraceAux(c, tos, pc) # XXX test if we want 'globalError' for every mode let lineInfo = if n == nil: c.debug[pc] else: n.info @@ -402,7 +402,7 @@ template handleJmpBack() {.dirty.} = if allowInfiniteLoops in c.features: c.loopIterations = MaxLoopIterations else: - msgWriteln("stack trace: (most recent call last)") + msgWriteln(c.config, "stack trace: (most recent call last)") stackTraceAux(c, tos, pc) globalError(c.config, c.debug[pc], errTooManyIterations) dec(c.loopIterations) @@ -907,13 +907,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcEcho: let rb = instr.regB if rb == 1: - msgWriteln(regs[ra].node.strVal, {msgStdout}) + msgWriteln(c.config, regs[ra].node.strVal, {msgStdout}) else: var outp = "" for i in ra..ra+rb-1: #if regs[i].kind != rkNode: debug regs[i] outp.add(regs[i].node.strVal) - msgWriteln(outp, {msgStdout}) + msgWriteln(c.config, outp, {msgStdout}) of opcContainsSet: decodeBC(rkInt) regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode)) @@ -1355,11 +1355,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = c.debug[pc].toFullPath, c.debug[pc].line.int, proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = if error.isNil and msg <= errMax: - error = formatMsg(info, msg, arg)) + error = formatMsg(conf, info, msg, arg)) if not error.isNil: c.errorFlag = error elif sonsLen(ast) != 1: - c.errorFlag = formatMsg(c.debug[pc], errGenerated, + c.errorFlag = formatMsg(c.config, c.debug[pc], errGenerated, "expected expression, but got multiple statements") else: regs[ra].node = ast.sons[0] @@ -1370,7 +1370,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = c.debug[pc].toFullPath, c.debug[pc].line.int, proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) = if error.isNil and msg <= errMax: - error = formatMsg(info, msg, arg)) + error = formatMsg(conf, info, msg, arg)) if not error.isNil: c.errorFlag = error else: From 328e7a100560e5bd179512ba142ef944bf0a0698 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 13 May 2018 17:52:21 +0200 Subject: [PATCH 198/214] options.nim: no global variables anymore --- compiler/ast.nim | 19 +-- compiler/ccgexprs.nim | 56 ++++---- compiler/ccgstmts.nim | 14 +- compiler/ccgthreadvars.nim | 6 +- compiler/ccgtrav.nim | 6 +- compiler/ccgtypes.nim | 4 +- compiler/cgen.nim | 102 +++++++------- compiler/cgendata.nim | 2 +- compiler/commands.nim | 270 ++++++++++++++++++------------------- compiler/docgen.nim | 50 +++---- compiler/docgen2.nim | 4 +- compiler/extccomp.nim | 58 ++++---- compiler/hlo.nim | 8 +- compiler/importer.nim | 3 +- compiler/jsgen.nim | 6 +- compiler/lambdalifting.nim | 23 ++-- compiler/lexer.nim | 6 +- compiler/lookups.nim | 8 +- compiler/lowerings.nim | 44 +++--- compiler/magicsys.nim | 4 +- compiler/main.nim | 74 +++++----- compiler/modulegraphs.nim | 2 +- compiler/modules.nim | 2 +- compiler/msgs.nim | 2 +- compiler/nim.nim | 10 +- compiler/nimconf.nim | 36 ++--- compiler/nimfix/nimfix.nim | 2 +- compiler/options.nim | 2 +- compiler/passaux.nim | 2 +- compiler/pragmas.nim | 31 ++--- compiler/renderer.nim | 4 +- compiler/rodread.nim | 15 +-- compiler/rodwrite.nim | 6 +- compiler/sem.nim | 10 +- compiler/semdata.nim | 5 +- compiler/semexprs.nim | 12 +- compiler/semfold.nim | 8 +- compiler/semgnrc.nim | 2 +- compiler/sempass2.nim | 10 +- compiler/semstmts.nim | 18 +-- compiler/semtypes.nim | 8 +- compiler/service.nim | 2 +- compiler/sigmatch.nim | 4 +- compiler/suggest.nim | 48 +++---- compiler/syntaxes.nim | 2 +- compiler/transf.nim | 6 +- 46 files changed, 509 insertions(+), 507 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 6785702f1c..5e65fbff90 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -734,7 +734,7 @@ type locOther # location is something other TLocFlag* = enum lfIndirect, # backend introduced a pointer - lfFullExternalName, # only used when 'gCmd == cmdPretty': Indicates + lfFullExternalName, # only used when 'conf.cmd == cmdPretty': Indicates # that the symbol has been imported via 'importc: "fullname"' and # no format string. lfNoDeepCopy, # no need for a deep copy @@ -1078,14 +1078,14 @@ template previouslyInferred*(t: PType): PType = if t.sons.len > 1: t.lastSon else: nil proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, - info: TLineInfo): PSym = + info: TLineInfo; options: TOptions = {}): PSym = # generates a symbol and initializes the hash field too new(result) result.name = name result.kind = symKind result.flags = {} result.info = info - result.options = gOptions + result.options = options result.owner = owner result.offset = -1 result.id = getID() @@ -1095,7 +1095,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, # writeStacktrace() # MessageOut(name.s & " has id: " & toString(result.id)) -var emptyNode* = newNode(nkEmpty) +var emptyNode* = newNode(nkEmpty) # XXX global variable here! # There is a single empty node that is shared! Do not overwrite it! proc isMetaType*(t: PType): bool = @@ -1325,7 +1325,7 @@ proc copyType*(t: PType, owner: PSym, keepId: bool): PType = proc exactReplica*(t: PType): PType = copyType(t, t.owner, true) proc copySym*(s: PSym, keepId: bool = false): PSym = - result = newSym(s.kind, s.name, s.owner, s.info) + result = newSym(s.kind, s.name, s.owner, s.info, s.options) #result.ast = nil # BUGFIX; was: s.ast which made problems result.typ = s.typ if keepId: @@ -1344,8 +1344,9 @@ proc copySym*(s: PSym, keepId: bool = false): PSym = if result.kind in {skVar, skLet, skField}: result.guard = s.guard -proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym = - result = newSym(s.kind, newIdent, s.owner, info) +proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo; + options: TOptions): PSym = + result = newSym(s.kind, newIdent, s.owner, info, options) # keep ID! result.ast = s.ast result.id = s.id @@ -1680,9 +1681,9 @@ proc isException*(t: PType): bool = base = base.lastSon return false -proc isImportedException*(t: PType): bool = +proc isImportedException*(t: PType; conf: ConfigRef): bool = assert(t != nil) - if optNoCppExceptions in gGlobalOptions: + if optNoCppExceptions in conf.globalOptions: return false let base = t.skipTypes({tyAlias, tyPtr, tyDistinct, tyGenericInst}) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index dff974ddbe..335aa2f84a 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -13,7 +13,7 @@ proc int64Literal(i: BiggestInt): Rope = if i > low(int64): - result = rfmt(nil, "IL64($1)", rope(i)) + result = "IL64($1)" % [rope(i)] else: result = ~"(IL64(-9223372036854775807) - IL64(1))" @@ -26,7 +26,7 @@ proc intLiteral(i: BiggestInt): Rope = # Nim has the same bug for the same reasons :-) result = ~"(-2147483647 -1)" elif i > low(int64): - result = rfmt(nil, "IL64($1)", rope(i)) + result = "IL64($1)" % [rope(i)] else: result = ~"(IL64(-9223372036854775807) - IL64(1))" @@ -834,7 +834,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = if field.loc.r == nil: internalError(p.config, e.info, "genCheckedRecordField") # generate the checks: genFieldCheck(p, e, r, field) - add(r, rfmt(nil, ".$1", field.loc.r)) + add(r, ropecg(p.module, ".$1", field.loc.r)) putIntoDest(p, d, e.sons[0], r, a.storage) else: genRecordField(p, e.sons[0], d) @@ -862,7 +862,7 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = localError(p.config, x.info, "index out of bounds") d.inheritLocation(a) putIntoDest(p, d, n, - rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage) + ropecg(p.module, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage) proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -871,7 +871,7 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) = var ty = skipTypes(a.t, abstractVarRange) inheritLocation(d, a) putIntoDest(p, d, n, - rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage) + ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage) proc genIndexCheck(p: BProc; arr, idx: TLoc) = let ty = skipTypes(arr.t, abstractVarRange) @@ -899,7 +899,7 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``! inheritLocation(d, a) putIntoDest(p, d, n, - rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage) + ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage) proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -919,9 +919,9 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = rdLoc(b), rdLoc(a), lenField(p)) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: - a.r = rfmt(nil, "(*$1)", a.r) + a.r = ropecg(p.module, "(*$1)", a.r) putIntoDest(p, d, n, - rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.storage) + ropecg(p.module, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.storage) proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) = var ty = skipTypes(n.sons[0].typ, abstractVarRange + tyUserTypeClasses) @@ -1004,7 +1004,7 @@ proc genEcho(p: BProc, n: PNode) = linefmt(p, cpsStmts, "fflush(stdout);$n") proc gcUsage(conf: ConfigRef; n: PNode) = - if gSelectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree) + if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree) proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = # @@ -1033,13 +1033,13 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[i + 1], a) if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar: inc(L) - add(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a))) + add(appends, ropecg(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a))) else: if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}: inc(L, len(e.sons[i + 1].strVal)) else: addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) - add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a))) + add(appends, ropecg(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a))) linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L)) add(p.s(cpsStmts), appends) if d.k == locNone: @@ -1071,14 +1071,14 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[i + 2], a) if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar: inc(L) - add(appends, rfmt(p.module, "#appendChar($1, $2);$n", + add(appends, ropecg(p.module, "#appendChar($1, $2);$n", rdLoc(dest), rdLoc(a))) else: if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}: inc(L, len(e.sons[i + 2].strVal)) else: addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) - add(appends, rfmt(p.module, "#appendString($1, $2);$n", + add(appends, ropecg(p.module, "#appendString($1, $2);$n", rdLoc(dest), rdLoc(a))) linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", rdLoc(dest), lens, rope(L)) @@ -1106,7 +1106,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = initLoc(dest, locExpr, e.sons[2], OnHeap) getIntTemp(p, tmpL) lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p)) - dest.r = rfmt(nil, "$1->data[$2]", rdLoc(a), tmpL.r) + dest.r = ropecg(p.module, "$1->data[$2]", rdLoc(a), tmpL.r) genAssignment(p, dest, b, {needToCopy, afDestIsNil}) gcUsage(p.config, e) @@ -1280,7 +1280,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = genNewSeqAux(p, dest[], intLiteral(sonsLen(n))) for i in countup(0, sonsLen(n) - 1): initLoc(arr, locExpr, n[i], OnHeap) - arr.r = rfmt(nil, "$1->data[$2]", rdLoc(dest[]), intLiteral(i)) + arr.r = ropecg(p.module, "$1->data[$2]", rdLoc(dest[]), intLiteral(i)) arr.storage = OnHeap # we know that sequences are on the heap expr(p, n[i], arr) gcUsage(p.config, n) @@ -1306,10 +1306,10 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = if L < 10: for i in countup(0, L - 1): initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap) - elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i)) + elem.r = ropecg(p.module, "$1->data[$2]", rdLoc(d), intLiteral(i)) elem.storage = OnHeap # we know that sequences are on the heap initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage) - arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i)) + arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), intLiteral(i)) genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) else: var i: TLoc @@ -1317,10 +1317,10 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = let oldCode = p.s(cpsStmts) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", i.r, L.rope) initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap) - elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), rdLoc(i)) + elem.r = ropecg(p.module, "$1->data[$2]", rdLoc(d), rdLoc(i)) elem.storage = OnHeap # we know that sequences are on the heap initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage) - arr.r = rfmt(nil, "$1[$2]", rdLoc(a), rdLoc(i)) + arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), rdLoc(i)) genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) lineF(p, cpsStmts, "}$n", []) @@ -1356,10 +1356,10 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope = inc p.module.labels let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache]) - result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache) + result = ropecg(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache) when false: # former version: - result = rfmt(p.module, "#isObj($1.m_type, $2)", + result = ropecg(p.module, "#isObj($1.m_type, $2)", a, genTypeInfo(p.module, dest, info)) proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = @@ -1372,7 +1372,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = while t.kind in {tyVar, tyLent, tyPtr, tyRef}: if t.kind notin {tyVar, tyLent}: nilCheck = r if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: - r = rfmt(nil, "(*$1)", r) + r = ropecg(p.module, "(*$1)", r) t = skipTypes(t.lastSon, typedescInst) discard getTypeDesc(p.module, t) if not p.module.compileToCpp: @@ -1383,9 +1383,9 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = globalError(p.config, x.info, "no 'of' operator available for pure objects") if nilCheck != nil: - r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info)) + r = ropecg(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info)) else: - r = rfmt(p.module, "($1)", genOfHelper(p, dest, r, x.info)) + r = ropecg(p.module, "($1)", genOfHelper(p, dest, r, x.info)) putIntoDest(p, d, x, r, a.storage) proc genOf(p: BProc, n: PNode, d: var TLoc) = @@ -1762,11 +1762,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "": initLocExpr(p, e.sons[2], x) putIntoDest(p, d, e, - rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) + ropecg(p.module, "(!($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, - rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) + ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) else: binaryExpr(p, e, d, "#eqStrings($1, $2)") @@ -1778,7 +1778,7 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) = assert(e.sons[2].typ != nil) initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) - putIntoDest(p, d, e, rfmt(nil, "(($4)($2) $1 ($4)($3))", + putIntoDest(p, d, e, ropecg(p.module, "(($4)($2) $1 ($4)($3))", rope(opr[m]), rdLoc(a), rdLoc(b), getSimpleTypeDesc(p.module, e[1].typ))) if optNaNCheck in p.options: @@ -2295,7 +2295,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = initLocExpr(p, ex, a) of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt: - if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions: + if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions: genTryCpp(p, n, d) else: genTry(p, n, d) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 0ba85488b4..1e0a3c818b 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -16,7 +16,7 @@ const # above X strings a hash-switch for strings is generated proc registerGcRoot(p: BProc, v: PSym) = - if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and + if p.config.selectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and containsGarbageCollectedRef(v.loc.t): # we register a specialized marked proc here; this has the advantage # that it works out of the box for thread local storage then :-) @@ -125,7 +125,7 @@ proc endBlock(p: BProc, blockEnd: Rope) = proc endBlock(p: BProc) = let topBlock = p.blocks.len - 1 var blockEnd = if p.blocks[topBlock].label != nil: - rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label) + ropecg(p.module, "} $1: ;$n", p.blocks[topBlock].label) else: ~"}$n" let frameLen = p.blocks[topBlock].frameLen @@ -337,7 +337,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = for i in countup(1, howManyTrys): let tryStmt = p.nestedTryStmts.pop - if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions: + if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions: # Pop safe points generated by try if not tryStmt.inExcept: linefmt(p, cpsStmts, "#popSafePoint();$n") @@ -356,7 +356,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = for i in countdown(howManyTrys-1, 0): p.nestedTryStmts.add(stack[i]) - if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions: + if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions: # Pop exceptions that was handled by the # except-blocks we are in for i in countdown(howManyExcepts-1, 0): @@ -571,7 +571,7 @@ proc genRaiseStmt(p: BProc, t: PNode) = var e = rdLoc(a) var typ = skipTypes(t[0].typ, abstractPtrs) genLineDir(p, t) - if isImportedException(typ): + if isImportedException(typ, p.config): lineF(p, cpsStmts, "throw $1;$n", [e]) else: lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n", @@ -579,7 +579,7 @@ proc genRaiseStmt(p: BProc, t: PNode) = else: genLineDir(p, t) # reraise the last exception: - if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions: + if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions: line(p, cpsStmts, ~"throw;$n") else: linefmt(p, cpsStmts, "#reraiseException();$n") @@ -1010,7 +1010,7 @@ proc genEmit(p: BProc, t: PNode) = if p.prc == nil: # top level emit pragma? let section = determineSection(t[1]) - genCLineDir(p.module.s[section], t.info) + genCLineDir(p.module.s[section], t.info, p.config) add(p.module.s[section], s) else: genLineDir(p, t) diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index c2ffa96519..da5c624b79 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -13,7 +13,7 @@ # included from cgen.nim proc emulatedThreadVars(conf: ConfigRef): bool = - result = {optThreads, optTlsEmulation} <= gGlobalOptions + result = {optThreads, optTlsEmulation} <= conf.globalOptions proc accessThreadLocalVar(p: BProc, s: PSym) = if emulatedThreadVars(p.config) and not p.threadVarAccessed: @@ -46,7 +46,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) = addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r]) else: if isExtern: add(m.s[cfsVars], "extern ") - if optThreads in gGlobalOptions: add(m.s[cfsVars], "NIM_THREADVAR ") + if optThreads in m.config.globalOptions: add(m.s[cfsVars], "NIM_THREADVAR ") add(m.s[cfsVars], getTypeDesc(m, s.loc.t)) addf(m.s[cfsVars], " $1;$n", [s.loc.r]) @@ -57,7 +57,7 @@ proc generateThreadLocalStorage(m: BModule) = proc generateThreadVarsSize(m: BModule) = if nimtv != nil: - let externc = if gCmd == cmdCompileToCpp or + let externc = if m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags: "extern \"C\" " else: "" addf(m.s[cfsProcs], diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 0e211e2390..c265064a19 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -77,7 +77,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", i.r, arraySize.rope) let oldLen = p.s(cpsStmts).len - genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1]) + genTraverseProc(c, ropecg(c.p.module, "$1[$2]", accessor, i.r), typ.sons[1]) if p.s(cpsStmts).len == oldLen: # do not emit dummy long loops for faster debug builds: p.s(cpsStmts) = oldCode @@ -92,12 +92,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = of tyTuple: let typ = getUniqueType(typ) for i in countup(0, sonsLen(typ) - 1): - genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i]) + genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i]) of tyRef, tyString, tySequence: lineCg(p, cpsStmts, c.visitorFrmt, accessor) of tyProc: if typ.callConv == ccClosure: - lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClE_0", accessor)) + lineCg(p, cpsStmts, c.visitorFrmt, ropecg(c.p.module, "$1.ClE_0", accessor)) else: discard diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index adebb6cd02..7b44cddad3 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -915,7 +915,7 @@ template cgDeclFrmt*(s: PSym): string = s.constraint.strVal proc genProcHeader(m: BModule, prc: PSym): Rope = var rettype, params: Rope - genCLineDir(result, prc.info) + genCLineDir(result, prc.info, m.config) # using static is needed for inline procs if lfExportLib in prc.loc.flags: if isHeaderFile in m.flags: @@ -1239,7 +1239,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = genTupleInfo(m, x, x, result, info) of tySequence, tyRef, tyOptAsRef: genTypeInfoAux(m, t, t, result, info) - if gSelectedGC >= gcMarkAndSweep: + if m.config.selectedGC >= gcMarkAndSweep: let markerProc = genTraverseProc(m, origType, sig) addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc]) of tyPtr, tyRange: genTypeInfoAux(m, t, t, result, info) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3a5d66762b..133e86cea5 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -93,6 +93,7 @@ proc useHeader(m: BModule, sym: PSym) = proc cgsym(m: BModule, name: string): Rope proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope = + assert m != nil var i = 0 var length = len(frmt) result = nil @@ -119,7 +120,7 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope = internalError(m.config, "ropes: invalid format string $" & $j) add(result, args[j-1]) of 'n': - if optLineDir notin gOptions: add(result, rnl) + if optLineDir notin m.config.options: add(result, rnl) inc(i) of 'N': add(result, rnl) @@ -146,9 +147,6 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope = if i - 1 >= start: add(result, substr(frmt, start, i - 1)) -template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped = - ropecg(m, fmt, args) - proc indentLine(p: BProc, r: Rope): Rope = result = r for i in countup(0, p.blocks.len-1): @@ -188,14 +186,14 @@ proc safeLineNm(info: TLineInfo): int = result = toLinenumber(info) if result < 0: result = 0 # negative numbers are not allowed in #line -proc genCLineDir(r: var Rope, filename: string, line: int) = +proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) = assert line >= 0 - if optLineDir in gOptions: + if optLineDir in conf.options: addf(r, "$N#line $2 $1$N", [rope(makeSingleLineCString(filename)), rope(line)]) -proc genCLineDir(r: var Rope, info: TLineInfo) = - genCLineDir(r, info.toFullPath, info.safeLineNm) +proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) = + genCLineDir(r, info.toFullPath, info.safeLineNm, conf) proc freshLineInfo(p: BProc; info: TLineInfo): bool = if p.lastLineInfo.line != info.line or @@ -212,9 +210,9 @@ proc genLineDir(p: BProc, t: PNode) = tt = tt.sons[1] let line = tt.info.safeLineNm - if optEmbedOrigSrc in gGlobalOptions: + if optEmbedOrigSrc in p.config.globalOptions: add(p.s(cpsStmts), ~"//" & sourceLine(p.config, tt.info) & rnl) - genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line) + genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line, p.config) if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and (p.prc == nil or sfPure notin p.prc.flags): if freshLineInfo(p, tt.info): @@ -235,7 +233,7 @@ proc emulatedThreadVars(conf: ConfigRef): bool {.inline.} proc genProc(m: BModule, prc: PSym) template compileToCpp(m: BModule): untyped = - gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags + m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags proc getTempName(m: BModule): Rope = result = m.tmpBase & rope(m.labels) @@ -416,7 +414,7 @@ proc assignLocalVar(p: BProc, n: PNode) = #assert(s.loc.k == locNone) # not yet assigned # this need not be fulfilled for inline procs; they are regenerated # for each module that uses them! - let nl = if optLineDir in gOptions: "" else: tnl + let nl = if optLineDir in p.config.options: "" else: tnl let decl = localVarDecl(p, n) & ";" & nl line(p, cpsLocals, decl) localDebugInfo(p, n.sym) @@ -510,24 +508,24 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope = discard cgsym(p.module, "nimFrame") if p.maxFrameLen > 0: discard cgsym(p.module, "VarSlot") - result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n", + result = ropecg(p.module, "\tnimfrs_($1, $2, $3, $4);$n", procname, filename, p.maxFrameLen.rope, p.blocks[0].frameLen.rope) else: - result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename) + result = ropecg(p.module, "\tnimfr_($1, $2);$n", procname, filename) proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope = discard cgsym(p.module, "nimFrame") addf(p.blocks[0].sections[cpsLocals], "TFrame $1;$n", [frame]) - result = rfmt(nil, "\t$1.procname = $2; $1.filename = $3; " & + result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " & " $1.line = $4; $1.len = -1; nimFrame(&$1);$n", frame, procname, filename, rope(line)) proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope = - result = rfmt(p.module, "\t#popFrameOfAddr(&$1);$n", frame) + result = ropecg(p.module, "\t#popFrameOfAddr(&$1);$n", frame) proc deinitFrame(p: BProc): Rope = - result = rfmt(p.module, "\t#popFrame();$n") + result = ropecg(p.module, "\t#popFrame();$n") include ccgexprs @@ -741,7 +739,7 @@ proc genProcAux(m: BModule, prc: PSym) = assignLocalVar(p, resNode) assert(res.loc.r != nil) initLocalVar(p, res, immediateAsgn=false) - returnStmt = rfmt(nil, "\treturn $1;$n", rdLoc(res.loc)) + returnStmt = ropecg(p.module, "\treturn $1;$n", rdLoc(res.loc)) else: fillResult(resNode) assignParam(p, res) @@ -763,10 +761,10 @@ proc genProcAux(m: BModule, prc: PSym) = if sfPure in prc.flags: if hasDeclspec in extccomp.CC[extccomp.cCompiler].props: header = "__declspec(naked) " & header - generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N", + generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N", header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)) else: - generatedProc = rfmt(nil, "$N$1 {$N", header) + generatedProc = ropecg(p.module, "$N$1 {$N", header) add(generatedProc, initGCFrame(p)) if optStackTrace in prc.options: add(generatedProc, p.s(cpsLocals)) @@ -790,10 +788,10 @@ proc genProcAux(m: BModule, prc: PSym) = proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} = result = (sfCompileToCpp in m.module.flags and sfCompileToCpp notin sym.getModule().flags and - gCmd != cmdCompileToCpp) or ( + m.config.cmd != cmdCompileToCpp) or ( sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and sym.magic == mNone and - gCmd == cmdCompileToCpp) + m.config.cmd == cmdCompileToCpp) proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) @@ -801,7 +799,7 @@ proc genProcPrototype(m: BModule, sym: PSym) = if lfDynamicLib in sym.loc.flags: if getModule(sym).id != m.module.id and not containsOrIncl(m.declaredThings, sym.id): - add(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n", + add(m.s[cfsVars], ropecg(m, "extern $1 $2;$n", getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym))) elif not containsOrIncl(m.declaredProtos, sym.id): var header = genProcHeader(m, sym) @@ -813,7 +811,7 @@ proc genProcPrototype(m: BModule, sym: PSym) = header.add(" __attribute__((naked))") if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props: header.add(" __attribute__((noreturn))") - add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) + add(m.s[cfsProcHeaders], ropecg(m, "$1;$n", header)) proc genProcNoForward(m: BModule, prc: PSym) = if lfImportCompilerProc in prc.loc.flags: @@ -919,14 +917,14 @@ proc genVarPrototype(m: BModule, n: PNode) = if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile") addf(m.s[cfsVars], " $1;$n", [sym.loc.r]) -proc addIntTypes(result: var Rope) {.inline.} = +proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} = addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl & "#define NIM_INTBITS $1" & tnl, [ platform.CPU[targetCPU].intSize.rope]) - if useNimNamespace : result.add("#define USE_NIM_NAMESPACE" & tnl) + if optUseNimNamespace in conf.globalOptions: result.add("#define USE_NIM_NAMESPACE" & tnl) proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = - if optCompileOnly in gGlobalOptions: + if optCompileOnly in conf.globalOptions: result = ("/* Generated by Nim Compiler v$1 */$N" & "/* (c) " & copyrightYear & " Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N") % @@ -945,7 +943,7 @@ proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope = result = getCopyright(conf, cfile) - addIntTypes(result) + addIntTypes(result, conf) proc genFilenames(m: BModule): Rope = discard cgsym(m, "dbgRegisterFilename") @@ -1050,8 +1048,8 @@ proc genMainProc(m: BModule) = var nimMain, otherMain: FormatStr if platform.targetOS == osWindows and - gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}: - if optGenGuiApp in gGlobalOptions: + m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: + if optGenGuiApp in m.config.globalOptions: nimMain = WinNimMain otherMain = WinCMain else: @@ -1061,7 +1059,7 @@ proc genMainProc(m: BModule) = elif platform.targetOS == osGenode: nimMain = GenodeNimMain otherMain = ComponentConstruct - elif optGenDynLib in gGlobalOptions: + elif optGenDynLib in m.config.globalOptions: nimMain = PosixNimDllMain otherMain = PosixCDllMain elif platform.targetOS == osStandalone: @@ -1071,11 +1069,11 @@ proc genMainProc(m: BModule) = nimMain = PosixNimMain otherMain = PosixCMain if m.g.breakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint") - if optEndb in gOptions: + if optEndb in m.config.options: m.g.breakpoints.add(m.genFilenames) let initStackBottomCall = - if platform.targetOS == osStandalone or gSelectedGC == gcNone: "".rope + if platform.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N") inc(m.labels) appcg(m, m.s[cfsProcs], PreMainBody, [ @@ -1088,12 +1086,12 @@ proc genMainProc(m: BModule) = appcg(m, m.s[cfsProcs], nimMain, [m.g.mainModInit, initStackBottomCall, rope(m.labels)]) - if optNoMain notin gGlobalOptions: - if useNimNamespace: + if optNoMain notin m.config.globalOptions: + if optUseNimNamespace in m.config.globalOptions: m.s[cfsProcs].add closeNamespaceNim() & "using namespace Nim;" & tnl appcg(m, m.s[cfsProcs], otherMain, []) - if useNimNamespace: m.s[cfsProcs].add openNamespaceNim() + if optUseNimNamespace in m.config.globalOptions: m.s[cfsProcs].add openNamespaceNim() proc getSomeInitName(m: PSym, suffix: string): Rope = assert m.kind == skModule @@ -1201,9 +1199,10 @@ proc genModule(m: BModule, cfile: Cfile): Rope = add(result, genSectionStart(i, m.config)) add(result, m.s[i]) add(result, genSectionEnd(i, m.config)) - if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim() + if optUseNimNamespace in m.config.globalOptions and i == cfsHeaders: + result.add openNamespaceNim() add(result, m.s[cfsInitProc]) - if useNimNamespace: result.add closeNamespaceNim() + if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim() proc newPreInitProc(m: BModule): BProc = result = newProc(nil, m) @@ -1216,10 +1215,12 @@ proc newPostInitProc(m: BModule): BProc = result.labels = 200_000 proc initProcOptions(m: BModule): TOptions = - if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions + let opts = m.config.options + if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule = new(result) + result.g = g result.tmpBase = rope("TM" & $hashOwner(module) & "_") result.headerFiles = @[] result.declaredThings = initIntSet() @@ -1240,14 +1241,13 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule = result.forwardedProcs = @[] result.typeNodesName = getTempName(result) result.nimTypesName = getTempName(result) - result.g = g # no line tracing for the init sections of the system module so that we # don't generate a TFrame which can confuse the stack botton initialization: if sfSystemModule in module.flags: incl result.flags, preventStackTrace excl(result.preInitProc.options, optStackTrace) excl(result.postInitProc.options, optStackTrace) - let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi") + let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi") else: "" open(result.ndi, ndiName) @@ -1316,7 +1316,7 @@ template injectG() {.dirty.} = proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = injectG() result = newModule(g, module) - if optGenIndex in gGlobalOptions and g.generatedHeader == nil: + if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil: let f = if graph.config.headerFile.len > 0: graph.config.headerFile else: graph.config.projectFull g.generatedHeader = rawNewModule(g, module, @@ -1331,7 +1331,7 @@ proc writeHeader(m: BModule) = var guard = "__$1__" % [m.filename.splitFile.name.rope] result.addf("#ifndef $1$n#define $1$n", [guard]) - addIntTypes(result) + addIntTypes(result, m.config) generateHeaders(m) generateThreadLocalStorage(m) @@ -1339,20 +1339,20 @@ proc writeHeader(m: BModule) = add(result, genSectionStart(i, m.config)) add(result, m.s[i]) add(result, genSectionEnd(i, m.config)) - if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim() + if optUseNimNamespace in m.config.globalOptions and i == cfsHeaders: result.add openNamespaceNim() add(result, m.s[cfsInitProc]) - if optGenDynLib in gGlobalOptions: + if optGenDynLib in m.config.globalOptions: result.add("N_LIB_IMPORT ") result.addf("N_CDECL(void, NimMain)(void);$n", []) - if useNimNamespace: result.add closeNamespaceNim() + if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim() result.addf("#endif /* $1 */$n", [guard]) writeRope(result, m.filename) proc getCFile(m: BModule): string = let ext = if m.compileToCpp: ".cpp" - elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m" + elif m.config.cmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m" else: ".c" result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext) @@ -1368,7 +1368,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode = var m = BModule(b) if passes.skipCodegen(m.config, n): return m.initProc.options = initProcOptions(m) - softRnl = if optLineDir in gOptions: noRnl else: rnl + softRnl = if optLineDir in m.config.options: noRnl else: rnl genStmts(m.initProc, n) proc finishModule(m: BModule) = @@ -1387,7 +1387,7 @@ proc finishModule(m: BModule) = proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = result = true - if optForceFullMake notin gGlobalOptions: + if optForceFullMake notin m.config.globalOptions: if not equalsFile(code, cfile.cname): if isDefined(m.config, "nimdiff"): if fileExists(cfile.cname): @@ -1412,7 +1412,7 @@ proc writeModule(m: BModule, pending: bool) = # generate code for the init statements of the module: let cfile = getCFile(m) - if m.rd == nil or optForceFullMake in gGlobalOptions: + if m.rd == nil or optForceFullMake in m.config.globalOptions: genInitCode(m) finishTypeDescriptions(m) if sfMainModule in m.module.flags: @@ -1423,7 +1423,7 @@ proc writeModule(m: BModule, pending: bool) = var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {}) var code = genModule(m, cf) when hasTinyCBackend: - if gCmd == cmdRun: + if conf.cmd == cmdRun: tccgen.compileCCode($code) return diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 0c310dd7d4..ce3fc2f905 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -170,7 +170,7 @@ proc newProc*(prc: PSym, module: BModule): BProc = result.prc = prc result.module = module if prc != nil: result.options = prc.options - else: result.options = gOptions + else: result.options = module.config.options newSeq(result.blocks, 1) result.nestedTryStmts = @[] result.finallySafePoints = @[] diff --git a/compiler/commands.nim b/compiler/commands.nim index 328dc2f02d..09f63f0f5b 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -61,49 +61,49 @@ proc getCommandLineDesc(): string = CPU[platform.hostCPU].name, CompileDate]) & Usage -proc helpOnError(pass: TCmdLinePass) = +proc helpOnError(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(getCommandLineDesc(), {msgStdout}) + msgWriteln(conf, getCommandLineDesc(), {msgStdout}) msgQuit(0) -proc writeAdvancedUsage(pass: TCmdLinePass) = +proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(`%`(HelpMessage, [VersionAsString, + msgWriteln(conf, (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, CPU[platform.hostCPU].name, CompileDate]) & AdvancedUsage, {msgStdout}) msgQuit(0) -proc writeFullhelp(pass: TCmdLinePass) = +proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(`%`(HelpMessage, [VersionAsString, + msgWriteln(conf, `%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, CPU[platform.hostCPU].name, CompileDate]) & Usage & AdvancedUsage, {msgStdout}) msgQuit(0) -proc writeVersionInfo(pass: TCmdLinePass) = +proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(`%`(HelpMessage, [VersionAsString, + msgWriteln(conf, `%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, CPU[platform.hostCPU].name, CompileDate]), {msgStdout}) const gitHash = gorge("git log -n 1 --format=%H").strip when gitHash.len == 40: - msgWriteln("git hash: " & gitHash, {msgStdout}) + msgWriteln(conf, "git hash: " & gitHash, {msgStdout}) - msgWriteln("active boot switches:" & usedRelease & + msgWriteln(conf, "active boot switches:" & usedRelease & usedTinyC & usedGnuReadline & usedNativeStacktrace & usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC, {msgStdout}) msgQuit(0) -proc writeCommandLineUsage*(helpWritten: var bool) = +proc writeCommandLineUsage*(conf: ConfigRef; helpWritten: var bool) = if not helpWritten: - msgWriteln(getCommandLineDesc(), {msgStdout}) + msgWriteln(conf, getCommandLineDesc(), {msgStdout}) helpWritten = true proc addPrefix(switch: string): string = @@ -137,24 +137,24 @@ proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TC proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "on": gOptions = gOptions + op - of "off": gOptions = gOptions - op + of "on": conf.options = conf.options + op + of "off": conf.options = conf.options - op else: localError(conf, info, errOnOrOffExpectedButXFound % arg) proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo): bool = result = false case arg.normalize - of "on": gOptions = gOptions + op - of "off": gOptions = gOptions - op + of "on": conf.options = conf.options + op + of "off": conf.options = conf.options - op of "list": result = true else: localError(conf, info, errOnOffOrListExpectedButXFound % arg) proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "on": gGlobalOptions = gGlobalOptions + op - of "off": gGlobalOptions = gGlobalOptions - op + of "on": conf.globalOptions = conf.globalOptions + op + of "off": conf.globalOptions = conf.globalOptions - op else: localError(conf, info, errOnOrOffExpectedButXFound % arg) proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = @@ -211,30 +211,30 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo case switch.normalize of "gc": case arg.normalize - of "boehm": result = gSelectedGC == gcBoehm - of "refc": result = gSelectedGC == gcRefc - of "v2": result = gSelectedGC == gcV2 - of "markandsweep": result = gSelectedGC == gcMarkAndSweep - of "generational": result = gSelectedGC == gcGenerational - of "go": result = gSelectedGC == gcGo - of "none": result = gSelectedGC == gcNone - of "stack", "regions": result = gSelectedGC == gcRegions + of "boehm": result = conf.selectedGC == gcBoehm + of "refc": result = conf.selectedGC == gcRefc + of "v2": result = conf.selectedGC == gcV2 + of "markandsweep": result = conf.selectedGC == gcMarkAndSweep + of "generational": result = conf.selectedGC == gcGenerational + of "go": result = conf.selectedGC == gcGo + of "none": result = conf.selectedGC == gcNone + of "stack", "regions": result = conf.selectedGC == gcRegions else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "opt": case arg.normalize - of "speed": result = contains(gOptions, optOptimizeSpeed) - of "size": result = contains(gOptions, optOptimizeSize) - of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {} + of "speed": result = contains(conf.options, optOptimizeSpeed) + of "size": result = contains(conf.options, optOptimizeSize) + of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {} else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg) - of "verbosity": result = $gVerbosity == arg + of "verbosity": result = $conf.verbosity == arg of "app": case arg.normalize - of "gui": result = contains(gGlobalOptions, optGenGuiApp) - of "console": result = not contains(gGlobalOptions, optGenGuiApp) - of "lib": result = contains(gGlobalOptions, optGenDynLib) and - not contains(gGlobalOptions, optGenGuiApp) - of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and - not contains(gGlobalOptions, optGenGuiApp) + of "gui": result = contains(conf.globalOptions, optGenGuiApp) + of "console": result = not contains(conf.globalOptions, optGenGuiApp) + of "lib": result = contains(conf.globalOptions, optGenDynLib) and + not contains(conf.globalOptions, optGenGuiApp) + of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and + not contains(conf.globalOptions, optGenGuiApp) else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg) of "dynliboverride": result = isDynlibOverride(conf, arg) @@ -242,42 +242,42 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool = case switch.normalize - of "debuginfo": result = contains(gGlobalOptions, optCDebug) - of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly) - of "nolinking": result = contains(gGlobalOptions, optNoLinking) - of "nomain": result = contains(gGlobalOptions, optNoMain) - of "forcebuild", "f": result = contains(gGlobalOptions, optForceFullMake) - of "warnings", "w": result = contains(gOptions, optWarns) - of "hints": result = contains(gOptions, optHints) - of "threadanalysis": result = contains(gGlobalOptions, optThreadAnalysis) - of "stacktrace": result = contains(gOptions, optStackTrace) - of "linetrace": result = contains(gOptions, optLineTrace) - of "debugger": result = contains(gOptions, optEndb) - of "profiler": result = contains(gOptions, optProfiler) - of "memtracker": result = contains(gOptions, optMemTracker) - of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions + of "debuginfo": result = contains(conf.globalOptions, optCDebug) + of "compileonly", "c": result = contains(conf.globalOptions, optCompileOnly) + of "nolinking": result = contains(conf.globalOptions, optNoLinking) + of "nomain": result = contains(conf.globalOptions, optNoMain) + of "forcebuild", "f": result = contains(conf.globalOptions, optForceFullMake) + of "warnings", "w": result = contains(conf.options, optWarns) + of "hints": result = contains(conf.options, optHints) + of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis) + of "stacktrace": result = contains(conf.options, optStackTrace) + of "linetrace": result = contains(conf.options, optLineTrace) + of "debugger": result = contains(conf.options, optEndb) + of "profiler": result = contains(conf.options, optProfiler) + of "memtracker": result = contains(conf.options, optMemTracker) + of "checks", "x": result = conf.options * ChecksOptions == ChecksOptions of "floatchecks": - result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck} - of "infchecks": result = contains(gOptions, optInfCheck) - of "nanchecks": result = contains(gOptions, optNaNCheck) - of "nilchecks": result = contains(gOptions, optNilCheck) - of "objchecks": result = contains(gOptions, optObjCheck) - of "fieldchecks": result = contains(gOptions, optFieldCheck) - of "rangechecks": result = contains(gOptions, optRangeCheck) - of "boundchecks": result = contains(gOptions, optBoundsCheck) - of "overflowchecks": result = contains(gOptions, optOverflowCheck) - of "movechecks": result = contains(gOptions, optMoveCheck) - of "linedir": result = contains(gOptions, optLineDir) - of "assertions", "a": result = contains(gOptions, optAssert) - of "run", "r": result = contains(gGlobalOptions, optRun) - of "symbolfiles": result = gSymbolFiles != disabledSf - of "genscript": result = contains(gGlobalOptions, optGenScript) - of "threads": result = contains(gGlobalOptions, optThreads) - of "taintmode": result = contains(gGlobalOptions, optTaintMode) - of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation) - of "implicitstatic": result = contains(gOptions, optImplicitStatic) - of "patterns": result = contains(gOptions, optPatterns) - of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace) + result = conf.options * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck} + of "infchecks": result = contains(conf.options, optInfCheck) + of "nanchecks": result = contains(conf.options, optNaNCheck) + of "nilchecks": result = contains(conf.options, optNilCheck) + of "objchecks": result = contains(conf.options, optObjCheck) + of "fieldchecks": result = contains(conf.options, optFieldCheck) + of "rangechecks": result = contains(conf.options, optRangeCheck) + of "boundchecks": result = contains(conf.options, optBoundsCheck) + of "overflowchecks": result = contains(conf.options, optOverflowCheck) + of "movechecks": result = contains(conf.options, optMoveCheck) + of "linedir": result = contains(conf.options, optLineDir) + of "assertions", "a": result = contains(conf.options, optAssert) + of "run", "r": result = contains(conf.globalOptions, optRun) + of "symbolfiles": result = conf.symbolFiles != disabledSf + of "genscript": result = contains(conf.globalOptions, optGenScript) + of "threads": result = contains(conf.globalOptions, optThreads) + of "taintmode": result = contains(conf.globalOptions, optTaintMode) + of "tlsemulation": result = contains(conf.globalOptions, optTlsEmulation) + of "implicitstatic": result = contains(conf.options, optImplicitStatic) + of "patterns": result = contains(conf.options, optPatterns) + of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace) else: invalidCmdLineOption(conf, passCmd1, switch, info) proc processPath(conf: ConfigRef; path: string, info: TLineInfo, @@ -353,7 +353,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; addPath(conf, if pass == passPP: processCfgPath(conf, arg, info) else: processPath(conf, arg, info), info) of "nimblepath", "babelpath": # keep the old name for compat - if pass in {passCmd2, passPP} and not options.gNoNimblePath: + if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions: expectArg(conf, switch, arg, pass, info) var path = processPath(conf, arg, info, notRelativeToProj=true) let nimbleDir = getEnv("NIMBLE_DIR") @@ -405,49 +405,49 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if pass in {passCmd2, passPP}: addExternalFileToLink(conf, arg) of "debuginfo": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optCDebug) + incl(conf.globalOptions, optCDebug) of "embedsrc": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optEmbedOrigSrc) + incl(conf.globalOptions, optEmbedOrigSrc) of "compileonly", "c": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optCompileOnly) + incl(conf.globalOptions, optCompileOnly) of "nolinking": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optNoLinking) + incl(conf.globalOptions, optNoLinking) of "nomain": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optNoMain) + incl(conf.globalOptions, optNoMain) of "forcebuild", "f": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optForceFullMake) + incl(conf.globalOptions, optForceFullMake) of "project": expectNoArg(conf, switch, arg, pass, info) - gWholeProject = true + incl conf.globalOptions, optWholeProject of "gc": expectArg(conf, switch, arg, pass, info) case arg.normalize of "boehm": - gSelectedGC = gcBoehm + conf.selectedGC = gcBoehm defineSymbol(conf.symbols, "boehmgc") of "refc": - gSelectedGC = gcRefc + conf.selectedGC = gcRefc of "v2": - gSelectedGC = gcV2 + conf.selectedGC = gcV2 of "markandsweep": - gSelectedGC = gcMarkAndSweep + conf.selectedGC = gcMarkAndSweep defineSymbol(conf.symbols, "gcmarkandsweep") of "generational": - gSelectedGC = gcGenerational + conf.selectedGC = gcGenerational defineSymbol(conf.symbols, "gcgenerational") of "go": - gSelectedGC = gcGo + conf.selectedGC = gcGo defineSymbol(conf.symbols, "gogc") of "none": - gSelectedGC = gcNone + conf.selectedGC = gcNone defineSymbol(conf.symbols, "nogc") of "stack", "regions": - gSelectedGC= gcRegions + conf.selectedGC= gcRegions defineSymbol(conf.symbols, "gcregions") else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "warnings", "w": @@ -463,29 +463,29 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "debugger": case arg.normalize of "on", "endb": - gOptions.incl optEndb + conf.options.incl optEndb defineSymbol(conf.symbols, "endb") of "off": - gOptions.excl optEndb + conf.options.excl optEndb undefSymbol(conf.symbols, "endb") of "native", "gdb": - incl(gGlobalOptions, optCDebug) - gOptions = gOptions + {optLineDir} - {optEndb} + incl(conf.globalOptions, optCDebug) + conf.options = conf.options + {optLineDir} - {optEndb} defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing undefSymbol(conf.symbols, "endb") else: localError(conf, info, "expected endb|gdb but found " & arg) of "profiler": processOnOffSwitch(conf, {optProfiler}, arg, pass, info) - if optProfiler in gOptions: defineSymbol(conf.symbols, "profiler") + if optProfiler in conf.options: defineSymbol(conf.symbols, "profiler") else: undefSymbol(conf.symbols, "profiler") of "memtracker": processOnOffSwitch(conf, {optMemTracker}, arg, pass, info) - if optMemTracker in gOptions: defineSymbol(conf.symbols, "memtracker") + if optMemTracker in conf.options: defineSymbol(conf.symbols, "memtracker") else: undefSymbol(conf.symbols, "memtracker") of "hotcodereloading": processOnOffSwitch(conf, {optHotCodeReloading}, arg, pass, info) - if optHotCodeReloading in gOptions: defineSymbol(conf.symbols, "hotcodereloading") + if optHotCodeReloading in conf.options: defineSymbol(conf.symbols, "hotcodereloading") else: undefSymbol(conf.symbols, "hotcodereloading") of "oldnewlines": case arg.normalize @@ -515,7 +515,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "deadcodeelim": discard # deprecated, dead code elim always on of "threads": processOnOffSwitchG(conf, {optThreads}, arg, pass, info) - #if optThreads in gGlobalOptions: incl(conf.notes, warnGcUnsafe) + #if optThreads in conf.globalOptions: incl(conf.notes, warnGcUnsafe) of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info) of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info) of "implicitstatic": @@ -526,34 +526,34 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; expectArg(conf, switch, arg, pass, info) case arg.normalize of "speed": - incl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) + incl(conf.options, optOptimizeSpeed) + excl(conf.options, optOptimizeSize) of "size": - excl(gOptions, optOptimizeSpeed) - incl(gOptions, optOptimizeSize) + excl(conf.options, optOptimizeSpeed) + incl(conf.options, optOptimizeSize) of "none": - excl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) + excl(conf.options, optOptimizeSpeed) + excl(conf.options, optOptimizeSize) else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg) of "app": expectArg(conf, switch, arg, pass, info) case arg.normalize of "gui": - incl(gGlobalOptions, optGenGuiApp) + incl(conf.globalOptions, optGenGuiApp) defineSymbol(conf.symbols, "executable") defineSymbol(conf.symbols, "guiapp") of "console": - excl(gGlobalOptions, optGenGuiApp) + excl(conf.globalOptions, optGenGuiApp) defineSymbol(conf.symbols, "executable") defineSymbol(conf.symbols, "consoleapp") of "lib": - incl(gGlobalOptions, optGenDynLib) - excl(gGlobalOptions, optGenGuiApp) + incl(conf.globalOptions, optGenDynLib) + excl(conf.globalOptions, optGenGuiApp) defineSymbol(conf.symbols, "library") defineSymbol(conf.symbols, "dll") of "staticlib": - incl(gGlobalOptions, optGenStaticLib) - excl(gGlobalOptions, optGenGuiApp) + incl(conf.globalOptions, optGenStaticLib) + excl(conf.globalOptions, optGenGuiApp) defineSymbol(conf.symbols, "library") defineSymbol(conf.symbols, "staticlib") else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg) @@ -574,7 +574,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if pass in {passCmd2, passPP}: cLinkedLibs.add processPath(conf, arg, info) of "header": if conf != nil: conf.headerFile = arg - incl(gGlobalOptions, optGenIndex) + incl(conf.globalOptions, optGenIndex) of "index": processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info) of "import": @@ -585,10 +585,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if pass in {passCmd2, passPP}: conf.implicitIncludes.add arg of "listcmd": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optListCmd) + incl(conf.globalOptions, optListCmd) of "genmapping": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optGenMapping) + incl(conf.globalOptions, optGenMapping) of "os": expectArg(conf, switch, arg, pass, info) if pass in {passCmd1, passPP}: @@ -605,53 +605,53 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; setTarget(targetOS, cpu) of "run", "r": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optRun) + incl(conf.globalOptions, optRun) of "verbosity": expectArg(conf, switch, arg, pass, info) - gVerbosity = parseInt(arg) - conf.notes = NotesVerbosity[gVerbosity] + conf.verbosity = parseInt(arg) + conf.notes = NotesVerbosity[conf.verbosity] incl(conf.notes, conf.enableNotes) excl(conf.notes, conf.disableNotes) conf.mainPackageNotes = conf.notes of "parallelbuild": expectArg(conf, switch, arg, pass, info) - gNumberOfProcessors = parseInt(arg) + conf.numberOfProcessors = parseInt(arg) of "version", "v": expectNoArg(conf, switch, arg, pass, info) - writeVersionInfo(pass) + writeVersionInfo(conf, pass) of "advanced": expectNoArg(conf, switch, arg, pass, info) - writeAdvancedUsage(pass) + writeAdvancedUsage(conf, pass) of "fullhelp": expectNoArg(conf, switch, arg, pass, info) - writeFullhelp(pass) + writeFullhelp(conf, pass) of "help", "h": expectNoArg(conf, switch, arg, pass, info) - helpOnError(pass) + helpOnError(conf, pass) of "symbolfiles": case arg.normalize - of "on": gSymbolFiles = enabledSf - of "off": gSymbolFiles = disabledSf - of "writeonly": gSymbolFiles = writeOnlySf - of "readonly": gSymbolFiles = readOnlySf - of "v2": gSymbolFiles = v2Sf + of "on": conf.symbolFiles = enabledSf + of "off": conf.symbolFiles = disabledSf + of "writeonly": conf.symbolFiles = writeOnlySf + of "readonly": conf.symbolFiles = readOnlySf + of "v2": conf.symbolFiles = v2Sf else: localError(conf, info, "invalid option for --symbolFiles: " & arg) of "skipcfg": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optSkipConfigFile) + incl(conf.globalOptions, optSkipConfigFile) of "skipprojcfg": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optSkipProjConfigFile) + incl(conf.globalOptions, optSkipProjConfigFile) of "skipusercfg": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optSkipUserConfigFile) + incl(conf.globalOptions, optSkipUserConfigFile) of "skipparentcfg": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optSkipParentConfigFiles) + incl(conf.globalOptions, optSkipParentConfigFiles) of "genscript", "gendeps": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optGenScript) - incl(gGlobalOptions, optCompileOnly) + incl(conf.globalOptions, optGenScript) + incl(conf.globalOptions, optCompileOnly) of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info) of "lib": expectArg(conf, switch, arg, pass, info) @@ -677,7 +677,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf.ideCmd = ideDef of "eval": expectArg(conf, switch, arg, pass, info) - gEvalExpr = arg + conf.evalExpr = arg of "context": expectNoArg(conf, switch, arg, pass, info) conf.ideCmd = ideCon @@ -686,15 +686,15 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf.ideCmd = ideUse of "stdout": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optStdout) + incl(conf.globalOptions, optStdout) of "listfullpaths": expectNoArg(conf, switch, arg, pass, info) - gListFullPaths = true + incl conf.globalOptions, optListFullPaths of "dynliboverride": dynlibOverride(conf, switch, arg, pass, info) of "dynliboverrideall": expectNoArg(conf, switch, arg, pass, info) - gDynlibOverrideAll = true + incl conf.globalOptions, optDynlibOverrideAll of "cs": # only supported for compatibility. Does nothing. expectArg(conf, switch, arg, pass, info) @@ -708,7 +708,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; localError(conf, info, "unknown experimental feature") of "nocppexceptions": expectNoArg(conf, switch, arg, pass, info) - incl(gGlobalOptions, optNoCppExceptions) + incl(conf.globalOptions, optNoCppExceptions) defineSymbol(conf.symbols, "noCppExceptions") of "cppdefine": expectArg(conf, switch, arg, pass, info) @@ -721,7 +721,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "nimNewRuntime") of "cppcompiletonamespace": expectNoArg(conf, switch, arg, pass, info) - useNimNamespace = true + incl conf.globalOptions, optUseNimNamespace defineSymbol(conf.symbols, "cppCompileToNamespace") else: if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 7fca27cc9e..7ab2f0eee1 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -29,7 +29,7 @@ type jArray: JsonNode types: TStrTable isPureRst: bool - conf: ConfigRef + conf*: ConfigRef PDoc* = ref TDocumentor ## Alias to type less. @@ -90,7 +90,7 @@ proc newDocumentor*(filename: string, conf: ConfigRef): PDoc = declareClosures() new(result) result.conf = conf - initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex), + initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex), conf.configVars, filename, {roSupportRawDirective}, docgenFindFile, compilerMsgHandler) @@ -117,8 +117,8 @@ proc newDocumentor*(filename: string, conf: ConfigRef): PDoc = result.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) = localError(conf, newLineInfo(conf, d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute") -proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) = - if gCmd != cmdRst2tex: addf(dest, xml, args) +proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) = + if conf.cmd != cmdRst2tex: addf(dest, xml, args) else: addf(dest, tex, args) proc getVarIdx(varnames: openArray[string], id: string): int = @@ -231,37 +231,37 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe of tkEof: break of tkComment: - dispA(result, "$1", "\\spanComment{$1}", + dispA(d.conf, result, "$1", "\\spanComment{$1}", [rope(esc(d.target, literal))]) of tokKeywordLow..tokKeywordHigh: - dispA(result, "$1", "\\spanKeyword{$1}", + dispA(d.conf, result, "$1", "\\spanKeyword{$1}", [rope(literal)]) of tkOpr: - dispA(result, "$1", "\\spanOperator{$1}", + dispA(d.conf, result, "$1", "\\spanOperator{$1}", [rope(esc(d.target, literal))]) of tkStrLit..tkTripleStrLit: - dispA(result, "$1", + dispA(d.conf, result, "$1", "\\spanStringLit{$1}", [rope(esc(d.target, literal))]) of tkCharLit: - dispA(result, "$1", "\\spanCharLit{$1}", + dispA(d.conf, result, "$1", "\\spanCharLit{$1}", [rope(esc(d.target, literal))]) of tkIntLit..tkUInt64Lit: - dispA(result, "$1", + dispA(d.conf, result, "$1", "\\spanDecNumber{$1}", [rope(esc(d.target, literal))]) of tkFloatLit..tkFloat128Lit: - dispA(result, "$1", + dispA(d.conf, result, "$1", "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))]) of tkSymbol: - dispA(result, "$1", + dispA(d.conf, result, "$1", "\\spanIdentifier{$1}", [rope(esc(d.target, literal))]) of tkSpaces, tkInvalid: add(result, literal) of tkCurlyDotLe: - dispA(result, """$1
""", + dispA(d.conf, result, """$1
""", "\\spanOther{$1}", [rope(esc(d.target, literal))]) of tkCurlyDotRi: - dispA(result, "
$1", + dispA(d.conf, result, "
$1", "\\spanOther{$1}", [rope(esc(d.target, literal))]) of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi, @@ -270,7 +270,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe tkAccent, tkColonColon, tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr, tkBracketLeColon: - dispA(result, "$1", "\\spanOther{$1}", + dispA(d.conf, result, "$1", "\\spanOther{$1}", [rope(esc(d.target, literal))]) proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) = @@ -278,7 +278,7 @@ proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) = of nkCallKinds: if n[0].kind == nkSym and n[0].sym.magic == mRunnableExamples and n.len >= 2 and n.lastSon.kind == nkStmtList: - dispA(dest, "\n$1\n", + dispA(d.conf, dest, "\n$1\n", "\n\\textbf{$1}\n", [rope"Examples:"]) inc d.listingCounter let id = $d.listingCounter @@ -509,7 +509,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = if gitUrl.len > 0: var commit = getConfigVar(d.conf, "git.commit") if commit.len == 0: commit = "master" - dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc, + dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc, ["path", "line", "url", "commit"], [rope path, rope($n.info.line), rope gitUrl, rope commit])]) @@ -578,7 +578,7 @@ proc traceDeps(d: PDoc, it: PNode) = traceDeps(d, a) else: if d.section[k] != nil: add(d.section[k], ", ") - dispA(d.section[k], + dispA(d.conf, d.section[k], "$1", "$1", [rope(getModuleName(d.conf, it))]) @@ -750,7 +750,7 @@ proc genOutFile(d: PDoc): Rope = "tableofcontents", "moduledesc", "date", "time", "content"], [title.rope, toc, d.modDesc, rope(getDateStr()), rope(getClockStr()), code]) - if optCompileOnly notin gGlobalOptions: + if optCompileOnly notin d.conf.globalOptions: # XXX what is this hack doing here? 'optCompileOnly' means raw output!? code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), ["title", "tableofcontents", "moduledesc", "date", "time", @@ -763,12 +763,12 @@ proc genOutFile(d: PDoc): Rope = result = code proc generateIndex*(d: PDoc) = - if optGenIndex in gGlobalOptions: + if optGenIndex in d.conf.globalOptions: writeIndexFile(d[], splitFile(d.conf.outFile).dir / splitFile(d.filename).name & IndexExt) proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string = - if gWholeProject: + if optWholeProject in conf.globalOptions: let d = if conf.outFile != "": conf.outFile else: dir createDir(d) result = d / changeFileExt(filename, ext) @@ -777,7 +777,7 @@ proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string = proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) = var content = genOutFile(d) - if optStdout in gGlobalOptions: + if optStdout in d.conf.globalOptions: writeRope(stdout, content) else: writeRope(content, getOutFile2(d.conf, filename, outExt, "htmldocs"), useWarning) @@ -787,7 +787,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string, let content = %*{"orig": d.filename, "nimble": getPackageName(d.conf, d.filename), "entries": d.jArray} - if optStdout in gGlobalOptions: + if optStdout in d.conf.globalOptions: write(stdout, $content) else: var f: File @@ -857,7 +857,7 @@ proc commandJson*(conf: ConfigRef) = let json = d.jArray let content = rope(pretty(json)) - if optStdout in gGlobalOptions: + if optStdout in d.conf.globalOptions: writeRope(stdout, content) else: #echo getOutFile(gProjectFull, JsonExt) @@ -872,7 +872,7 @@ proc commandTags*(conf: ConfigRef) = content: Rope generateTags(d, ast, content) - if optStdout in gGlobalOptions: + if optStdout in d.conf.globalOptions: writeRope(stdout, content) else: #echo getOutFile(gProjectFull, TagsExt) diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index c975e6cc7c..d9a73e1cd5 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -25,8 +25,8 @@ template closeImpl(body: untyped) {.dirty.} = var g = PGen(p) let useWarning = sfMainModule notin g.module.flags #echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId - if (g.module.owner.id == gMainPackageId and gWholeProject) or - sfMainModule in g.module.flags: + if (g.module.owner.id == gMainPackageId and optWholeProject in g.doc.conf.globalOptions) or + sfMainModule in g.module.flags: body try: generateIndex(g.doc) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 8f67a7fb69..3f0e6f611f 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -390,7 +390,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = suffix if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and - optCompileOnly notin gGlobalOptions: + optCompileOnly notin conf.globalOptions: let fullCCname = platform.CPU[targetCPU].name & '.' & platform.OS[targetOS].name & '.' & CC[c].name & fullSuffix @@ -496,7 +496,7 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} = # really: Cross compilation from Linux to Linux for example is entirely # reasonable. # `optGenMapping` is included here for niminst. - result = gGlobalOptions * {optGenScript, optGenMapping} != {} + result = conf.globalOptions * {optGenScript, optGenMapping} != {} proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string = result = compileOptions @@ -505,15 +505,15 @@ proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string = addOpt(result, option) let trunk = splitFile(cfilename).name - if optCDebug in gGlobalOptions: + if optCDebug in conf.globalOptions: let key = trunk & ".debug" if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) else: addOpt(result, getDebug(conf, cCompiler)) - if optOptimizeSpeed in gOptions: + if optOptimizeSpeed in conf.options: let key = trunk & ".speed" if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) else: addOpt(result, getOptSpeed(conf, cCompiler)) - elif optOptimizeSize in gOptions: + elif optOptimizeSize in conf.options: let key = trunk & ".size" if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key)) else: addOpt(result, getOptSize(conf, cCompiler)) @@ -531,7 +531,7 @@ proc getLinkOptions(conf: ConfigRef): string = result.add(join([CC[cCompiler].linkDirCmd, libDir.quoteShell])) proc needsExeExt(conf: ConfigRef): bool {.inline.} = - result = (optGenScript in gGlobalOptions and targetOS == osWindows) or + result = (optGenScript in conf.globalOptions and targetOS == osWindows) or (platform.hostOS == osWindows) proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string = @@ -556,7 +556,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string = if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname) if needsExeExt(conf): exe = addFileExt(exe, "exe") - if optGenDynLib in gGlobalOptions and + if optGenDynLib in conf.globalOptions and ospNeedsPIC in platform.OS[targetOS].props: add(options, ' ' & CC[c].pic) @@ -628,7 +628,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = close(f) proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) = - if optForceFullMake notin gGlobalOptions and not externalFileChanged(conf, c): + if optForceFullMake notin conf.globalOptions and not externalFileChanged(conf, c): c.flags.incl CfileFlag.Cached toCompile.add(c) @@ -644,16 +644,16 @@ proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var # call the C compiler for the .c file: if it.flags.contains(CfileFlag.Cached): continue var compileCmd = getCompileCFileCmd(conf, it) - if optCompileOnly notin gGlobalOptions: + if optCompileOnly notin conf.globalOptions: add(cmds, compileCmd) let (_, name, _) = splitFile(it.cname) add(prettyCmds, "CC: " & name) - if optGenScript in gGlobalOptions: + if optGenScript in conf.globalOptions: add(script, compileCmd) add(script, tnl) proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = - if optGenStaticLib in gGlobalOptions: + if optGenStaticLib in conf.globalOptions: var libname: string if conf.outFile.len > 0: libname = conf.outFile.expandTilde @@ -670,10 +670,10 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe") if noAbsolutePaths(conf): result = linkerExe else: result = joinPath(ccompilerpath, linkerExe) - let buildgui = if optGenGuiApp in gGlobalOptions: CC[cCompiler].buildGui + let buildgui = if optGenGuiApp in conf.globalOptions: CC[cCompiler].buildGui else: "" var exefile, builddll: string - if optGenDynLib in gGlobalOptions: + if optGenDynLib in conf.globalOptions: exefile = platform.OS[targetOS].dllFrmt % splitFile(projectfile).name builddll = CC[cCompiler].buildDll else: @@ -687,7 +687,7 @@ proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string = if not exefile.isAbsolute(): exefile = joinPath(splitFile(projectfile).dir, exefile) when false: - if optCDebug in gGlobalOptions: + if optCDebug in conf.globalOptions: writeDebugInfo(exefile.changeFileExt("ndb")) exefile = quoteShell(exefile) let linkOptions = getLinkOptions(conf) & " " & @@ -720,7 +720,7 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body proc execLinkCmd(conf: ConfigRef; linkCmd: string) = tryExceptOSErrorMessage(conf, "invocation of external linker program failed."): execExternalProgram(conf, linkCmd, - if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking) + if optListCmd in conf.globalOptions or conf.verbosity > 1: hintExecuting else: hintLinking) proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: int)) = let runCb = proc (idx: int, p: Process) = @@ -729,9 +729,9 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: rawMessage(conf, errGenerated, "execution of an external compiler program '" & cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" & p.outputStream.readAll.strip) - if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors() + if conf.numberOfProcessors == 0: conf.numberOfProcessors = countProcessors() var res = 0 - if gNumberOfProcessors <= 1: + if conf.numberOfProcessors <= 1: for i in countup(0, high(cmds)): tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."): res = execWithEcho(conf, cmds[i]) @@ -740,24 +740,24 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: cmds[i]) else: tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."): - if optListCmd in gGlobalOptions or gVerbosity > 1: + if optListCmd in conf.globalOptions or conf.verbosity > 1: res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath}, - gNumberOfProcessors, afterRunEvent=runCb) - elif gVerbosity == 1: + conf.numberOfProcessors, afterRunEvent=runCb) + elif conf.verbosity == 1: res = execProcesses(cmds, {poStdErrToStdOut, poUsePath}, - gNumberOfProcessors, prettyCb, afterRunEvent=runCb) + conf.numberOfProcessors, prettyCb, afterRunEvent=runCb) else: res = execProcesses(cmds, {poStdErrToStdOut, poUsePath}, - gNumberOfProcessors, afterRunEvent=runCb) + conf.numberOfProcessors, afterRunEvent=runCb) if res != 0: - if gNumberOfProcessors <= 1: + if conf.numberOfProcessors <= 1: rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" % cmds.join()) proc callCCompiler*(conf: ConfigRef; projectfile: string) = var linkCmd: string - if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: + if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: return # speed up that call if only compiling and no script shall be # generated #var c = cCompiler @@ -767,9 +767,9 @@ proc callCCompiler*(conf: ConfigRef; projectfile: string) = let prettyCb = proc (idx: int) = echo prettyCmds[idx] compileCFile(conf, toCompile, script, cmds, prettyCmds) - if optCompileOnly notin gGlobalOptions: + if optCompileOnly notin conf.globalOptions: execCmdsInParallel(conf, cmds, prettyCb) - if optNoLinking notin gGlobalOptions: + if optNoLinking notin conf.globalOptions: # call the linker: var objfiles = "" for it in externalToLink: @@ -783,11 +783,11 @@ proc callCCompiler*(conf: ConfigRef; projectfile: string) = add(objfiles, quoteShell(objFile)) linkCmd = getLinkCmd(conf, projectfile, objfiles) - if optCompileOnly notin gGlobalOptions: + if optCompileOnly notin conf.globalOptions: execLinkCmd(conf, linkCmd) else: linkCmd = "" - if optGenScript in gGlobalOptions: + if optGenScript in conf.globalOptions: add(script, linkCmd) add(script, tnl) generateScript(conf, projectfile, script) @@ -892,7 +892,7 @@ proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope = addf(result, "--file:r\"$1\"$N", [rope(it.cname)]) proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) = - if optGenMapping notin gGlobalOptions: return + if optGenMapping notin conf.globalOptions: return var code = rope("[C_Files]\n") add(code, genMappingFiles(conf, toCompile)) add(code, "\n[C_Compiler]\nFlags=") diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 76404e49b6..8251e3179c 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -17,7 +17,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode = # aweful to semcheck before macro invocation, so we don't and treat # templates and macros as immediate in this context. var rule: string - if optHints in gOptions and hintPattern in c.config.notes: + if optHints in c.config.options and hintPattern in c.config.notes: rule = renderTree(n, {renderNoComments}) let s = n.sons[0].sym case s.kind @@ -27,7 +27,7 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode = result = semTemplateExpr(c, n, s, {efFromHlo}) else: result = semDirectOp(c, n, {}) - if optHints in gOptions and hintPattern in c.config.notes: + if optHints in c.config.options and hintPattern in c.config.notes: message(c.config, orig.info, hintPattern, rule & " --> '" & renderTree(result, {renderNoComments}) & "'") @@ -92,12 +92,12 @@ proc hlo(c: PContext, n: PNode): PNode = proc hloBody(c: PContext, n: PNode): PNode = # fast exit: - if c.patterns.len == 0 or optPatterns notin gOptions: return n + if c.patterns.len == 0 or optPatterns notin c.config.options: return n c.hloLoopDetector = 0 result = hlo(c, n) proc hloStmt(c: PContext, n: PNode): PNode = # fast exit: - if c.patterns.len == 0 or optPatterns notin gOptions: return n + if c.patterns.len == 0 or optPatterns notin c.config.options: return n c.hloLoopDetector = 0 result = hlo(c, n) diff --git a/compiler/importer.nim b/compiler/importer.nim index 4e3aa8d101..ed988cea72 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -122,7 +122,8 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym = localError(c.config, n.info, "module alias must be an identifier") elif n.sons[1].ident.id != realModule.name.id: # some misguided guy will write 'import abc.foo as foo' ... - result = createModuleAlias(realModule, n.sons[1].ident, realModule.info) + result = createModuleAlias(realModule, n.sons[1].ident, realModule.info, + c.config.options) proc myImportModule(c: PContext, n: PNode): PSym = var f = checkModuleName(c.config, n) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 2ec5a068d6..25b554f7b0 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -245,7 +245,7 @@ proc mangleName(m: BModule, s: PSym): Rope = inc i result = rope(x) if s.name.s != "this" and s.kind != skField: - if optHotCodeReloading in gOptions: + if optHotCodeReloading in m.config.options: # When hot reloading is enabled, we must ensure that the names # of functions and types will be preserved across rebuilds: add(result, idOrSig(s, m.module.name.s, m.sigConflicts)) @@ -1425,7 +1425,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = s: Rope varCode: string varName = mangleName(p.module, v) - useReloadingGuard = sfGlobal in v.flags and optHotCodeReloading in gOptions + useReloadingGuard = sfGlobal in v.flags and optHotCodeReloading in p.config.options if v.constraint.isNil: if useReloadingGuard: @@ -1970,7 +1970,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = else: result = ~tnl - if optHotCodeReloading in gOptions: + if optHotCodeReloading in p.config.options: # Here, we introduce thunks that create the equivalent of a jump table # for all global functions, because references to them may be stored # in JavaScript variables. The added indirection ensures that such diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 2410f1d368..773e5e29c5 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -137,7 +137,7 @@ proc createStateType(g: ModuleGraph; iter: PSym): PType = rawAddSon(result, intType) proc createStateField(g: ModuleGraph; iter: PSym): PSym = - result = newSym(skField, getIdent(":state"), iter, iter.info) + result = newSym(skField, getIdent(":state"), iter, iter.info, {}) result.typ = createStateType(g, iter) proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType = @@ -151,7 +151,7 @@ proc getIterResult(iter: PSym): PSym = result = iter.ast.sons[resultPos].sym else: # XXX a bit hacky: - result = newSym(skResult, getIdent":result", iter, iter.info) + result = newSym(skResult, getIdent":result", iter, iter.info, {}) result.typ = iter.typ.sons[0] incl(result.flags, sfUsed) iter.ast.add newSymNode(result) @@ -228,14 +228,14 @@ proc interestingIterVar(s: PSym): bool {.inline.} = template isIterator*(owner: PSym): bool = owner.kind == skIterator and owner.typ.callConv == ccClosure -proc liftingHarmful(owner: PSym): bool {.inline.} = +proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} = ## lambda lifting can be harmful for JS-like code generators. let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro - result = gCmd == cmdCompileToJS and not isCompileTime + result = conf.cmd == cmdCompileToJS and not isCompileTime proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) - if liftingHarmful(owner): return n + if liftingHarmful(g.config, owner): return n let iter = n.sym assert iter.isIterator @@ -811,14 +811,14 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNo fn.typ.callConv = oldCC proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode = - # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs + # XXX conf.cmd == cmdCompileToJS does not suffice! The compiletime stuff needs # the transformation even when compiling to JS ... # However we can do lifting for the stuff which is *only* compiletime. let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro if body.kind == nkEmpty or ( - gCmd == cmdCompileToJS and not isCompileTime) or + g.config.cmd == cmdCompileToJS and not isCompileTime) or fn.skipGenericOwner.kind != skModule: # ignore forward declaration: result = body @@ -842,11 +842,8 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PN # echo renderTree(result, {renderIds}) proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode = - if body.kind == nkEmpty or gCmd == cmdCompileToJS: - result = body - else: - # XXX implement it properly - result = body + # XXX implement it properly + result = body # ------------------- iterator transformation -------------------------------- @@ -878,7 +875,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode = nkBreakState(cl.state) ... """ - if liftingHarmful(owner): return body + if liftingHarmful(g.config, owner): return body var L = body.len if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds): localError(g.config, body.info, "ignored invalid for loop") diff --git a/compiler/lexer.nim b/compiler/lexer.nim index d01b8c4be8..5915619877 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -190,8 +190,8 @@ proc prettyTok*(tok: TToken): string = if isKeyword(tok.tokType): result = "keyword " & tok.ident.s else: result = tokToStr(tok) -proc printTok*(tok: TToken) = - msgWriteln($tok.line & ":" & $tok.col & "\t" & +proc printTok*(conf: ConfigRef; tok: TToken) = + msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & TokTypeToStr[tok.tokType] & " " & tokToStr(tok)) proc initToken*(L: var TToken) = @@ -714,7 +714,7 @@ proc handleCRLF(L: var TLexer, pos: int): int = if col > MaxLineLength: lexMessagePos(L, hintLineTooLong, pos) - if optEmbedOrigSrc in gGlobalOptions: + if optEmbedOrigSrc in L.config.globalOptions: let lineStart = cast[ByteAddress](L.buf) + L.lineStart let line = newString(cast[cstring](lineStart), col) addSourceLine(L.fileIdx, line) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index e161d2e11f..b6d63d0bd4 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -85,7 +85,7 @@ proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym = result = s else: result = s.owner - if gCmd == cmdPretty: + if conf.cmd == cmdPretty: prettybase.replaceDeprecated(n.info, s, result) else: message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " & @@ -128,11 +128,11 @@ proc errorSym*(c: PContext, n: PNode): PSym = considerQuotedIdent(c.config, m) else: getIdent("err:" & renderTree(m)) - result = newSym(skError, ident, getCurrOwner(c), n.info) + result = newSym(skError, ident, getCurrOwner(c), n.info, {}) result.typ = errorType(c) incl(result.flags, sfDiscardable) # pretend it's imported from some unknown module to prevent cascading errors: - if gCmd != cmdInteractive and c.compilesContextId == 0: + if c.config.cmd != cmdInteractive and c.compilesContextId == 0: c.importTable.addSym(result) type @@ -176,7 +176,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = s = nextIter(it, scope.symbols) proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string) = - if gCmd != cmdInteractive: + if c.config.cmd != cmdInteractive: localError(c.config, info, "redefinition of '$1'" % s) proc addDecl*(c: PContext, sym: PSym, info: TLineInfo) = diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 5b85ab008f..13336f00e1 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -49,7 +49,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode = let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info) + var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info, g.config.options) temp.typ = skipTypes(value.typ, abstractInst) incl(temp.flags, sfFromGeneric) @@ -77,7 +77,7 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode = let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skLet, getIdent("_"), owner, value.info) + var temp = newSym(skLet, getIdent("_"), owner, value.info, owner.options) var v = newNodeI(nkLetSection, value.info) let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) @@ -95,7 +95,7 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode = proc lowerSwap*(n: PNode; owner: PSym): PNode = result = newNodeI(nkStmtList, n.info) # note: cannot use 'skTemp' here cause we really need the copy for the VM :-( - var temp = newSym(skVar, getIdent(genPrefix), owner, n.info) + var temp = newSym(skVar, getIdent(genPrefix), owner, n.info, owner.options) temp.typ = n.sons[1].typ incl(temp.flags, sfFromGeneric) @@ -121,7 +121,7 @@ proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType rawAddSon(result, getCompilerProc(g, "RootObj").typ) result.n = newNodeI(nkRecList, info) let s = newSym(skType, getIdent("Env_" & info.toFilename), - owner, info) + owner, info, owner.options) incl s.flags, sfAnon s.typ = result result.sym = s @@ -174,7 +174,8 @@ proc lookupInRecord(n: PNode, id: int): PSym = proc addField*(obj: PType; s: PSym) = # because of 'gensym' support, we have to mangle the name with its ID. # This is hacky but the clean solution is much more complex than it looks. - var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info) + var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info, + s.options) field.id = -s.id let t = skipIntLit(s.typ) field.typ = t @@ -185,7 +186,8 @@ proc addField*(obj: PType; s: PSym) = proc addUniqueField*(obj: PType; s: PSym): PSym {.discardable.} = result = lookupInRecord(obj.n, s.id) if result == nil: - var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info) + var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info, + s.options) field.id = -s.id let t = skipIntLit(s.typ) field.typ = t @@ -335,7 +337,8 @@ proc typeNeedsNoDeepCopy(t: PType): bool = proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType; v: PNode; useShallowCopy=false): PSym = - result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info) + result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info, + owner.options) result.typ = typ incl(result.flags, sfFromGeneric) @@ -449,7 +452,8 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; t.n.add argsParam.newSymNode let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper" - result = newSym(skProc, getIdent(name), argsParam.owner, f.info) + result = newSym(skProc, getIdent(name), argsParam.owner, f.info, + argsParam.options) result.ast = newProcNode(nkProcDef, f.info, body, params, newSymNode(result)) result.typ = t @@ -475,7 +479,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchOb # localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure") let fieldname = if i < formals.len: formals[i].sym.name else: tmpName - var field = newSym(skField, fieldname, objType.owner, n.info) + var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options) field.typ = argType objType.addField(field) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) @@ -529,7 +533,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb # localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure") let fieldname = if i < formals.len: formals[i].sym.name else: tmpName - var field = newSym(skField, fieldname, objType.owner, n.info) + var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options) if argType.kind in {tyVarargs, tyOpenArray}: # important special case: we always create a zero-copy slice: @@ -537,7 +541,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb slice.typ = n.typ slice.sons[0] = newSymNode(createMagic(g, "slice", mSlice)) slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type - var fieldB = newSym(skField, tmpName, objType.owner, n.info) + var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options) fieldB.typ = getSysType(g, n.info, tyInt) objType.addField(fieldB) @@ -547,7 +551,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchOb objType.addField(field) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - var fieldA = newSym(skField, tmpName, objType.owner, n.info) + var fieldA = newSym(skField, tmpName, objType.owner, n.info, g.config.options) fieldA.typ = getSysType(g, n.info, tyInt) objType.addField(fieldA) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) @@ -615,12 +619,12 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P if n.kind notin nkCallKinds: localError(g.config, n.info, "'spawn' takes a call expression") return - if optThreadAnalysis in gGlobalOptions: + if optThreadAnalysis in g.config.globalOptions: if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}: localError(g.config, n.info, "'spawn' takes a GC safe call expression") var - threadParam = newSym(skParam, getIdent"thread", owner, n.info) - argsParam = newSym(skParam, getIdent"args", owner, n.info) + threadParam = newSym(skParam, getIdent"thread", owner, n.info, g.config.options) + argsParam = newSym(skParam, getIdent"args", owner, n.info, g.config.options) block: let ptrType = getSysType(g, n.info, tyPointer) threadParam.typ = ptrType @@ -631,7 +635,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P incl(objType.flags, tfFinal) let castExpr = createCastExpr(argsParam, objType) - var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info) + var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info, g.config.options) block: scratchObj.typ = objType incl(scratchObj.flags, sfFromGeneric) @@ -649,7 +653,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P skFunc, skMethod, skConverter}): # for indirect calls we pass the function pointer in the scratchObj var argType = n[0].typ.skipTypes(abstractInst) - var field = newSym(skField, getIdent"fn", owner, n.info) + var field = newSym(skField, getIdent"fn", owner, n.info, g.config.options) field.typ = argType objType.addField(field) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) @@ -673,7 +677,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P if barrier != nil: let typ = newType(tyPtr, owner) typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) - var field = newSym(skField, getIdent"barrier", owner, n.info) + var field = newSym(skField, getIdent"barrier", owner, n.info, g.config.options) field.typ = typ objType.addField(field) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier) @@ -681,7 +685,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P var fvField, fvAsExpr: PNode = nil if spawnKind == srFlowVar: - var field = newSym(skField, getIdent"fv", owner, n.info) + var field = newSym(skField, getIdent"fv", owner, n.info, g.config.options) field.typ = retType objType.addField(field) fvField = newDotExpr(scratchObj, field) @@ -692,7 +696,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField) elif spawnKind == srByVar: - var field = newSym(skField, getIdent"fv", owner, n.info) + var field = newSym(skField, getIdent"fv", owner, n.info, g.config.options) field.typ = newType(tyPtr, objType.owner) field.typ.rawAddSon(retType) objType.addField(field) diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index aabcfd7a6a..b5577d9610 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -29,7 +29,7 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = result = strTableGet(g.systemModule.tab, getIdent(name)) if result == nil: localError(g.config, info, "system module needs: " & name) - result = newSym(skError, getIdent(name), g.systemModule, g.systemModule.info) + result = newSym(skError, getIdent(name), g.systemModule, g.systemModule.info, {}) result.typ = newType(tyError, g.systemModule) if result.kind == skStub: loadStub(result) if result.kind == skAlias: result = result.owner @@ -57,7 +57,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy r = nextIdentIter(ti, g.systemModule.tab) if result != nil: return result localError(g.config, info, "system module needs: " & name) - result = newSym(skError, id, g.systemModule, g.systemModule.info) + result = newSym(skError, id, g.systemModule, g.systemModule.info, {}) result.typ = newType(tyError, g.systemModule) proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType = diff --git a/compiler/main.nim b/compiler/main.nim index b9afc6a8dc..69b33653bc 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -20,8 +20,8 @@ import from magicsys import resetSysTypes -proc rodPass = - if gSymbolFiles in {enabledSf, writeOnlySf}: +proc rodPass(g: ModuleGraph) = + if g.config.symbolFiles in {enabledSf, writeOnlySf}: registerPass(rodwritePass) proc codegenPass = @@ -56,7 +56,7 @@ proc commandCheck(graph: ModuleGraph; cache: IdentCache) = graph.config.errorMax = high(int) # do not stop after first error defineSymbol(graph.config.symbols, "nimcheck") semanticPasses() # use an empty backend for semantic checking only - rodPass() + rodPass(graph) compileProject(graph, cache) proc commandDoc2(graph: ModuleGraph; cache: IdentCache; json: bool) = @@ -73,16 +73,16 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) = extccomp.initVars(conf) semanticPasses() registerPass(cgenPass) - rodPass() + rodPass(graph) #registerPass(cleanupPass()) compileProject(graph, cache) cgenWriteModules(graph.backend, conf) - if gCmd != cmdRun: + if conf.cmd != cmdRun: let proj = changeFileExt(conf.projectFull, "") extccomp.callCCompiler(conf, proj) extccomp.writeJsonBuildInstructions(conf, proj) - if optGenScript in gGlobalOptions: + if optGenScript in graph.config.globalOptions: writeDepsFile(graph, toGeneratedFile(conf, proj, "")) proc commandJsonScript(graph: ModuleGraph; cache: IdentCache) = @@ -144,7 +144,7 @@ proc commandScan(cache: IdentCache, config: ConfigRef) = openLexer(L, f, stream, cache, config) while true: rawGetTok(L, tok) - printTok(tok) + printTok(config, tok) if tok.tokType == tkEof: break closeLexer(L) else: @@ -159,78 +159,78 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = setupModuleCache() # In "nim serve" scenario, each command must reset the registered passes clearPasses() - gLastCmdTime = epochTime() + conf.lastCmdTime = epochTime() conf.searchPaths.add(conf.libpath) setId(100) case conf.command.normalize of "c", "cc", "compile", "compiletoc": # compile means compileToC currently - gCmd = cmdCompileToC + conf.cmd = cmdCompileToC commandCompileToC(graph, cache) of "cpp", "compiletocpp": - gCmd = cmdCompileToCpp + conf.cmd = cmdCompileToCpp defineSymbol(graph.config.symbols, "cpp") commandCompileToC(graph, cache) of "objc", "compiletooc": - gCmd = cmdCompileToOC + conf.cmd = cmdCompileToOC defineSymbol(graph.config.symbols, "objc") commandCompileToC(graph, cache) of "run": - gCmd = cmdRun + conf.cmd = cmdRun when hasTinyCBackend: extccomp.setCC("tcc") commandCompileToC(graph, cache) else: rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") of "js", "compiletojs": - gCmd = cmdCompileToJS + conf.cmd = cmdCompileToJS commandCompileToJS(graph, cache) of "doc0": wantMainModule(conf) - gCmd = cmdDoc + conf.cmd = cmdDoc loadConfigs(DocConfig, cache) commandDoc(conf) of "doc2", "doc": - gCmd = cmdDoc + conf.cmd = cmdDoc loadConfigs(DocConfig, cache) defineSymbol(conf.symbols, "nimdoc") commandDoc2(graph, cache, false) of "rst2html": - gCmd = cmdRst2html + conf.cmd = cmdRst2html loadConfigs(DocConfig, cache) commandRst2Html(conf) of "rst2tex": - gCmd = cmdRst2tex + conf.cmd = cmdRst2tex loadConfigs(DocTexConfig, cache) commandRst2TeX(conf) of "jsondoc0": wantMainModule(conf) - gCmd = cmdDoc + conf.cmd = cmdDoc loadConfigs(DocConfig, cache) wantMainModule(conf) defineSymbol(conf.symbols, "nimdoc") commandJson(conf) of "jsondoc2", "jsondoc": - gCmd = cmdDoc + conf.cmd = cmdDoc loadConfigs(DocConfig, cache) wantMainModule(conf) defineSymbol(conf.symbols, "nimdoc") commandDoc2(graph, cache, true) of "ctags": wantMainModule(conf) - gCmd = cmdDoc + conf.cmd = cmdDoc loadConfigs(DocConfig, cache) defineSymbol(conf.symbols, "nimdoc") commandTags(conf) of "buildindex": - gCmd = cmdDoc + conf.cmd = cmdDoc loadConfigs(DocConfig, cache) commandBuildIndex(conf) of "gendepend": - gCmd = cmdGenDepend + conf.cmd = cmdGenDepend commandGenDepend(graph, cache) of "dump": - gCmd = cmdDump + conf.cmd = cmdDump if getConfigVar(conf, "dump.format") == "json": wantMainModule(conf) @@ -247,48 +247,48 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = (key: "lib_paths", val: libpaths) ] - msgWriteln($dumpdata, {msgStdout, msgSkipHook}) + msgWriteln(conf, $dumpdata, {msgStdout, msgSkipHook}) else: - msgWriteln("-- list of currently defined symbols --", + msgWriteln(conf, "-- list of currently defined symbols --", {msgStdout, msgSkipHook}) - for s in definedSymbolNames(conf.symbols): msgWriteln(s, {msgStdout, msgSkipHook}) - msgWriteln("-- end of list --", {msgStdout, msgSkipHook}) + for s in definedSymbolNames(conf.symbols): msgWriteln(conf, s, {msgStdout, msgSkipHook}) + msgWriteln(conf, "-- end of list --", {msgStdout, msgSkipHook}) - for it in conf.searchPaths: msgWriteln(it) + for it in conf.searchPaths: msgWriteln(conf, it) of "check": - gCmd = cmdCheck + conf.cmd = cmdCheck commandCheck(graph, cache) of "parse": - gCmd = cmdParse + conf.cmd = cmdParse wantMainModule(conf) discard parseFile(FileIndex conf.projectMainIdx, cache, conf) of "scan": - gCmd = cmdScan + conf.cmd = cmdScan wantMainModule(conf) commandScan(cache, conf) - msgWriteln("Beware: Indentation tokens depend on the parser's state!") + msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!") of "secret": - gCmd = cmdInteractive + conf.cmd = cmdInteractive commandInteractive(graph, cache) of "e": commandEval(graph, cache, mainCommandArg(conf)) of "nop", "help": # prevent the "success" message: - gCmd = cmdDump + conf.cmd = cmdDump of "jsonscript": - gCmd = cmdJsonScript + conf.cmd = cmdJsonScript commandJsonScript(graph, cache) else: rawMessage(conf, errGenerated, "invalid command: " & conf.command) if conf.errorCounter == 0 and - gCmd notin {cmdInterpret, cmdRun, cmdDump}: + conf.cmd notin {cmdInterpret, cmdRun, cmdDump}: when declared(system.getMaxMem): let usedMem = formatSize(getMaxMem()) & " peakmem" else: let usedMem = formatSize(getTotalMem()) rawMessage(conf, hintSuccessX, [$conf.linesCompiled, - formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3), + formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3), usedMem, if isDefined(conf, "release"): "Release Build" else: "Debug Build"]) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index da39651864..460d0b4a5c 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -59,7 +59,7 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} = result = doStopCompile != nil and doStopCompile() proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = - result = newSym(skProc, getIdent(name), nil, unknownLineInfo()) + result = newSym(skProc, getIdent(name), nil, unknownLineInfo(), {}) result.magic = m proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = diff --git a/compiler/modules.nim b/compiler/modules.nim index 3da1bbbc72..7bc32d42cc 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -66,7 +66,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f gMainPackageId = result.owner.id when false: - if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: + if conf.cmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: rd = handleSymbolFile(result, cache) if result.id < 0: internalError("handleSymbolFile should have set the module's ID") diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 6586c9992b..774a8b83ca 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -313,7 +313,7 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = ## This is used for 'nim dump' etc. where we don't have nimsuggest ## support. - #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return + #if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return if not isNil(writelnHook) and msgSkipHook notin flags: writelnHook(s) diff --git a/compiler/nim.nim b/compiler/nim.nim index d8402a2af6..d3e00017f5 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -40,7 +40,7 @@ proc prependCurDir(f: string): string = proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = condsyms.initDefines(conf.symbols) if paramCount() == 0: - writeCommandLineUsage(conf.helpWritten) + writeCommandLineUsage(conf, conf.helpWritten) else: # Process command line arguments: processCmdLine(passCmd1, "", conf) @@ -76,14 +76,14 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = if conf.command == "": rawMessage(conf, errGenerated, "command missing") mainCommand(newModuleGraph(conf), cache) - if optHints in gOptions and hintGCStats in conf.notes: echo(GC_getStatistics()) + if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics()) #echo(GC_getStatistics()) if conf.errorCounter == 0: when hasTinyCBackend: - if gCmd == cmdRun: + if conf.cmd == cmdRun: tccgen.run(conf.arguments) - if optRun in gGlobalOptions: - if gCmd == cmdCompileToJS: + if optRun in conf.globalOptions: + if conf.cmd == cmdCompileToJS: var ex: string if conf.outFile.len > 0: ex = conf.outFile.prependCurDir.quoteShell diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 6a26f8dc74..379d15ad68 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -123,7 +123,7 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack of wEnd: doEnd(L, tok, condStack) of wWrite: ppGetTok(L, tok) - msgs.msgWriteln(strtabs.`%`(tokToStr(tok), config.configVars, + msgs.msgWriteln(config, strtabs.`%`(tokToStr(tok), config.configVars, {useEnvironment, useKey})) ppGetTok(L, tok) else: @@ -230,30 +230,30 @@ proc getSystemConfigPath(conf: ConfigRef; filename: string): string = if not existsFile(result): result = joinPath([p, "etc", filename]) if not existsFile(result): result = "/etc/" & filename -proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) = - setDefaultLibpath(config) +proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef = nil) = + setDefaultLibpath(conf) - if optSkipConfigFile notin gGlobalOptions: - readConfigFile(getSystemConfigPath(config, cfg), cache, config) + if optSkipConfigFile notin conf.globalOptions: + readConfigFile(getSystemConfigPath(conf, cfg), cache, conf) - if optSkipUserConfigFile notin gGlobalOptions: - readConfigFile(getUserConfigPath(cfg), cache, config) + if optSkipUserConfigFile notin conf.globalOptions: + readConfigFile(getUserConfigPath(cfg), cache, conf) - let pd = if config.projectPath.len > 0: config.projectPath else: getCurrentDir() - if optSkipParentConfigFiles notin gGlobalOptions: + let pd = if conf.projectPath.len > 0: conf.projectPath else: getCurrentDir() + if optSkipParentConfigFiles notin conf.globalOptions: for dir in parentDirs(pd, fromRoot=true, inclusive=false): - readConfigFile(dir / cfg, cache, config) + readConfigFile(dir / cfg, cache, conf) - if optSkipProjConfigFile notin gGlobalOptions: - readConfigFile(pd / cfg, cache, config) + if optSkipProjConfigFile notin conf.globalOptions: + readConfigFile(pd / cfg, cache, conf) - if config.projectName.len != 0: + if conf.projectName.len != 0: # new project wide config file: - var projectConfig = changeFileExt(config.projectFull, "nimcfg") + var projectConfig = changeFileExt(conf.projectFull, "nimcfg") if not fileExists(projectConfig): - projectConfig = changeFileExt(config.projectFull, "nim.cfg") - readConfigFile(projectConfig, cache, config) + projectConfig = changeFileExt(conf.projectFull, "nim.cfg") + readConfigFile(projectConfig, cache, conf) -proc loadConfigs*(cfg: string; config: ConfigRef) = +proc loadConfigs*(cfg: string; conf: ConfigRef) = # for backwards compatibility only. - loadConfigs(cfg, newIdentCache(), config) + loadConfigs(cfg, newIdentCache(), conf) diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim index 2ef375b002..c3e29f9a12 100644 --- a/compiler/nimfix/nimfix.nim +++ b/compiler/nimfix/nimfix.nim @@ -38,7 +38,7 @@ In addition, all command line options of Nim are supported. proc mainCommand = registerPass verbosePass registerPass semPass - gCmd = cmdPretty + conf.cmd = cmdPretty searchPaths.add options.libpath if gProjectFull.len != 0: # current path is always looked first for modules diff --git a/compiler/options.nim b/compiler/options.nim index c918cac685..56c3dcf0b7 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -70,7 +70,7 @@ type # please make sure we have under 32 options optIdeTerse # idetools: use terse descriptions optNoCppExceptions # use C exception handling even with CPP optExcessiveStackTrace # fully qualified module filenames - opWholeProject # for 'doc2': output any dependency + optWholeProject # for 'doc2': output any dependency optListFullPaths optNoNimblePath optDynlibOverrideAll diff --git a/compiler/passaux.nim b/compiler/passaux.nim index f0d6bd44a8..568fb4c23c 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -26,7 +26,7 @@ proc verboseOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext = proc verboseProcess(context: PPassContext, n: PNode): PNode = result = n let v = VerboseRef(context) - if gVerbosity == 3: + if v.config.verbosity == 3: # system.nim deactivates all hints, for verbosity:3 we want the processing # messages nonetheless, so we activate them again unconditionally: incl(v.config.notes, hintProcessing) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 31d3f75a36..1bb10b80ef 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -116,7 +116,7 @@ proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) = s.loc.r = rope(extname % s.name.s) except ValueError: localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)") - if gCmd == cmdPretty and '$' notin extname: + if c.config.cmd == cmdPretty and '$' notin extname: # note that '{.importc.}' is transformed into '{.importc: "$1".}' s.loc.flags.incl(lfFullExternalName) @@ -140,7 +140,7 @@ proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) = incl(s.flags, sfImportc) incl(s.flags, sfInfixCall) excl(s.flags, sfForward) - if gCmd == cmdCompileToC: + if c.config.cmd == cmdCompileToC: let m = s.getModule() incl(m.flags, sfCompileToCpp) extccomp.gMixedMode = true @@ -218,8 +218,8 @@ proc isTurnedOn(c: PContext, n: PNode): bool = localError(c.config, n.info, "'on' or 'off' expected") proc onOff(c: PContext, n: PNode, op: TOptions) = - if isTurnedOn(c, n): gOptions = gOptions + op - else: gOptions = gOptions - op + if isTurnedOn(c, n): c.config.options = c.config.options + op + else: c.config.options = c.config.options - op proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) = if isTurnedOn(c, n): incl(c.module.flags, flag) @@ -343,14 +343,14 @@ proc processOption(c: PContext, n: PNode): bool = else: case n.sons[1].ident.s.normalize of "speed": - incl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) + incl(c.config.options, optOptimizeSpeed) + excl(c.config.options, optOptimizeSize) of "size": - excl(gOptions, optOptimizeSpeed) - incl(gOptions, optOptimizeSize) + excl(c.config.options, optOptimizeSpeed) + incl(c.config.options, optOptimizeSize) of "none": - excl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) + excl(c.config.options, optOptimizeSpeed) + excl(c.config.options, optOptimizeSize) else: localError(c.config, n.info, "'none', 'speed' or 'size' expected") of wImplicitStatic: onOff(c, n, {optImplicitStatic}) of wPatterns: onOff(c, n, {optPatterns}) @@ -361,7 +361,7 @@ proc processPush(c: PContext, n: PNode, start: int) = localError(c.config, n.info, "'push' cannot have arguments") var x = newOptionEntry(c.config) var y = c.optionStack[^1] - x.options = gOptions + x.options = c.config.options x.defaultCC = y.defaultCC x.dynlib = y.dynlib x.notes = c.config.notes @@ -378,7 +378,7 @@ proc processPop(c: PContext, n: PNode) = if c.optionStack.len <= 1: localError(c.config, n.info, "{.pop.} without a corresponding {.push.}") else: - gOptions = c.optionStack[^1].options + c.config.options = c.optionStack[^1].options c.config.notes = c.optionStack[^1].notes c.optionStack.setLen(c.optionStack.len - 1) @@ -557,7 +557,7 @@ proc processPragma(c: PContext, n: PNode, i: int) = elif it[0].kind != nkIdent: invalidPragma(c, n) elif it[1].kind != nkIdent: invalidPragma(c, n) - var userPragma = newSym(skTemplate, it[1].ident, nil, it.info) + var userPragma = newSym(skTemplate, it[1].ident, nil, it.info, c.config.options) userPragma.ast = newNode(nkPragma, n.info, n.sons[i+1..^1]) strTableAdd(c.userPragmas, userPragma) @@ -635,7 +635,7 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) = if dest == nil or dest.kind in routineKinds: localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines") let src = considerQuotedIdent(c.config, n[0]) - let alias = newSym(skAlias, src, dest, n[0].info) + let alias = newSym(skAlias, src, dest, n[0].info, c.config.options) incl(alias.flags, sfExported) if sfCompilerProc in dest.flags: markCompilerProc(c, alias) addInterfaceDecl(c, alias) @@ -657,7 +657,8 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym = # We return a dummy symbol; later passes over the type will repair it. # Generic instantiation needs to know about this too. But we're lazy # and perform the lookup on demand instead. - result = newSym(skUnknown, considerQuotedIdent(c.config, n), nil, n.info) + result = newSym(skUnknown, considerQuotedIdent(c.config, n), nil, n.info, + c.config.options) else: result = qualifiedLookUp(c, n, {checkUndeclared}) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index a47c77464f..966bed7697 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1456,9 +1456,7 @@ proc renderModule*(n: PNode, infile, outfile: string, nkCommentStmt: putNL(g) else: discard gcoms(g) - if optStdout in gGlobalOptions: - write(stdout, g.buf) - elif open(f, outfile, fmWrite): + if open(f, outfile, fmWrite): write(f, g.buf) close(f) else: diff --git a/compiler/rodread.nim b/compiler/rodread.nim index f62c24dfd5..52e7a924c6 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -623,16 +623,16 @@ proc processRodFile(r: PRodReader, hash: SecureHash) = of "OPTIONS": inc(r.pos) # skip ':' r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos))) - if options.gOptions != r.options: r.reason = rrOptions + if r.config.options != r.options: r.reason = rrOptions of "GOPTIONS": inc(r.pos) # skip ':' var dep = cast[TGlobalOptions](int32(decodeVInt(r.s, r.pos))) - if gGlobalOptions-harmlessOptions != dep-harmlessOptions: + if r.config.globalOptions-harmlessOptions != dep-harmlessOptions: r.reason = rrOptions of "CMD": inc(r.pos) # skip ':' var dep = cast[TCommands](int32(decodeVInt(r.s, r.pos))) - if cmdChangeTriggersRecompilation(dep, gCmd): r.reason = rrOptions + if cmdChangeTriggersRecompilation(dep, r.config.cmd): r.reason = rrOptions of "DEFINES": inc(r.pos) # skip ':' d = 0 @@ -907,7 +907,7 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache; conf: ConfigRef): TReasonFo # we cannot break here, because of side-effects of `checkDep` if result != rrNone: rawMessage(conf, hintProcessing, reasonToFrmt[result] % filename) - if result != rrNone or optForceFullMake in gGlobalOptions: + if result != rrNone or optForceFullMake in conf.globalOptions: # recompilation is necessary: if r != nil: memfiles.close(r.memfile) r = nil @@ -915,7 +915,7 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache; conf: ConfigRef): TReasonFo gMods[fileIdx.int32].reason = result # now we know better proc handleSymbolFile*(module: PSym; cache: IdentCache; conf: ConfigRef): PRodReader = - if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}: + if conf.symbolFiles in {disabledSf, writeOnlySf, v2Sf}: module.id = getID() return nil idgen.loadMaxIds(conf, conf.projectPath / conf.projectName) @@ -1035,9 +1035,8 @@ proc writeSym(f: File; s: PSym) = if s.magic != mNone: f.write('@') f.write($s.magic) - if s.options != gOptions: - f.write('!') - f.write($s.options) + f.write('!') + f.write($s.options) if s.position != 0: f.write('%') f.write($s.position) diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 7dc10bbf56..4686baf2b7 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -71,7 +71,7 @@ proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache; result.hash = hash result.module = module result.defines = getDefines(config) - result.options = options.gOptions + result.options = config.options result.files = @[] result.inclDeps = "" result.modDeps = "" @@ -509,12 +509,12 @@ proc writeRod(w: PRodWriter) = f.write(rodNL) var goptions = "GOPTIONS:" - encodeVInt(cast[int32](gGlobalOptions), goptions) + encodeVInt(cast[int32](w.config.globalOptions), goptions) f.write(goptions) f.write(rodNL) var cmd = "CMD:" - encodeVInt(cast[int32](gCmd), cmd) + encodeVInt(cast[int32](w.config.cmd), cmd) f.write(cmd) f.write(rodNL) diff --git a/compiler/sem.nim b/compiler/sem.nim index 8cb233a056..c5c3dd99bc 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -64,7 +64,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode; # templates perform some quick check whether the cursor is actually in # the generic or template. when defined(nimsuggest): - if gCmd == cmdIdeTools and requiresCheck: + if c.config.cmd == cmdIdeTools and requiresCheck: #if optIdeDebug in gGlobalOptions: # echo "passing to safeSemExpr: ", renderTree(n) discard safeSemExpr(c, n) @@ -562,9 +562,9 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = if result.kind != nkEmpty: addSon(a, result) result = a result = hloStmt(c, result) - if gCmd == cmdInteractive and not isEmptyType(result.typ): + if c.config.cmd == cmdInteractive and not isEmptyType(result.typ): result = buildEchoStmt(c, result) - if gCmd == cmdIdeTools: + if c.config.cmd == cmdIdeTools: appendToModule(c.module, result) result = transformStmt(c.graph, c.module, result) @@ -595,7 +595,7 @@ proc myProcess(context: PPassContext, n: PNode): PNode = result = nil else: result = ast.emptyNode - #if gCmd == cmdIdeTools: findSuggest(c, n) + #if c.config.cmd == cmdIdeTools: findSuggest(c, n) rod.storeNode(c.module, result) proc testExamples(c: PContext) = @@ -612,7 +612,7 @@ proc testExamples(c: PContext) = proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = var c = PContext(context) - if gCmd == cmdIdeTools and not c.suggestionsMade: + if c.config.cmd == cmdIdeTools and not c.suggestionsMade: suggestSentinel(c) closeScope(c) # close module's scope rawCloseScope(c) # imported symbols; don't check for unused ones! diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 6f7a48dae2..ad5bdfd497 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -204,7 +204,7 @@ proc considerGenSyms*(c: PContext; n: PNode) = proc newOptionEntry*(conf: ConfigRef): POptionEntry = new(result) - result.options = gOptions + result.options = conf.options result.defaultCC = ccDefault result.dynlib = nil result.notes = conf.notes @@ -286,7 +286,8 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = let typedesc = makeTypeDesc(c, typ) - let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info).linkTo(typedesc) + let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info, + c.config.options).linkTo(typedesc) return newSymNode(sym, info) proc makeTypeFromExpr*(c: PContext, n: PNode): PType = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5fe7a7a699..2a2a8b72af 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -481,7 +481,7 @@ proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr) proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = - if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or + if n.kind == nkHiddenDeref and not (c.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags): checkSonsLen(n, 1, c.config) result = n.sons[0] @@ -601,7 +601,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and {sfForward, sfImportc} * callee.flags == {} and n.typ != nil: if sfCompileTime notin callee.flags and - optImplicitStatic notin gOptions: return + optImplicitStatic notin c.config.options: return if callee.magic notin ctfeWhitelist: return if callee.kind notin {skProc, skFunc, skConverter} or callee.isGenericRoutine: @@ -1078,7 +1078,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # here at all! #if isSymChoice(n.sons[1]): return when defined(nimsuggest): - if gCmd == cmdIdeTools: + if c.config.cmd == cmdIdeTools: suggestExpr(c, n) if exactEquals(gTrackPos, n[1].info): suggestExprNoCheck(c, n) @@ -1931,7 +1931,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = if callee.magic != mNone: result = magicsAfterOverloadResolution(c, result, flags) of mRunnableExamples: - if gCmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList: + if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList: if sfMainModule in c.module.flags: let inp = toFullPath(c.module.info) if c.runnableExamples == nil: @@ -2205,7 +2205,7 @@ proc shouldBeBracketExpr(n: PNode): bool = proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = n - if gCmd == cmdIdeTools: suggestExpr(c, n) + if c.config.cmd == cmdIdeTools: suggestExpr(c, n) if nfSem in n.flags: return case n.kind of nkIdent, nkAccQuoted: @@ -2290,7 +2290,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = 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: + #if c.config.cmd == cmdPretty and n.sons[0].kind == nkDotExpr: # pretty.checkUse(n.sons[0].sons[1].info, s) case s.kind of skMacro: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 48a81d1105..daf9ce983a 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -403,11 +403,11 @@ proc magicCall(m: PSym, n: PNode; g: ModuleGraph): PNode = result = evalOp(s.magic, n, a, b, c, g) proc getAppType(n: PNode; g: ModuleGraph): PNode = - if gGlobalOptions.contains(optGenDynLib): + if g.config.globalOptions.contains(optGenDynLib): result = newStrNodeT("lib", n, g) - elif gGlobalOptions.contains(optGenStaticLib): + elif g.config.globalOptions.contains(optGenStaticLib): result = newStrNodeT("staticlib", n, g) - elif gGlobalOptions.contains(optGenGuiApp): + elif g.config.globalOptions.contains(optGenGuiApp): result = newStrNodeT("gui", n, g) else: result = newStrNodeT("console", n, g) @@ -479,7 +479,7 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode = result = newNodeIT(nkCharLit, x.info, n.typ) if idx >= 0 and idx < len(x.strVal): result.intVal = ord(x.strVal[int(idx)]) - elif idx == len(x.strVal) and optLaxStrings in gOptions: + elif idx == len(x.strVal) and optLaxStrings in g.config.options: discard else: localError(g.config, n.info, "index out of bounds: " & $n) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index a620c544dd..8f06e748e2 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -169,7 +169,7 @@ proc semGenericStmt(c: PContext, n: PNode, when defined(nimsuggest): if withinTypeDesc in flags: inc c.inTypeContext - #if gCmd == cmdIdeTools: suggestStmt(c, n) + #if conf.cmd == cmdIdeTools: suggestStmt(c, n) semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody) case n.kind diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 015e81b1fd..5431615242 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -146,7 +146,7 @@ proc guardDotAccess(a: PEffects; n: PNode) = proc makeVolatile(a: PEffects; s: PSym) {.inline.} = template compileToCpp(a): untyped = - gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags + a.config.cmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags if a.inTryStmt > 0 and not compileToCpp(a): incl(s.flags, sfVolatile) @@ -186,7 +186,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = a.owner.gcUnsafetyReason = reason.sym else: a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent(""), - a.owner, reason.info) + a.owner, reason.info, {}) when true: template markSideEffect(a: PEffects; reason: typed) = @@ -282,7 +282,7 @@ proc addEffect(a: PEffects, e: PNode, useLineInfo=true) = var aa = a.exc for i in a.bottom ..< aa.len: if sameType(a.graph.excType(aa[i]), a.graph.excType(e)): - if not useLineInfo or gCmd == cmdDoc: return + if not useLineInfo or a.config.cmd == cmdDoc: return elif aa[i].info == e.info: return throws(a.exc, e) @@ -290,7 +290,7 @@ proc addTag(a: PEffects, e: PNode, useLineInfo=true) = var aa = a.tags for i in 0 ..< aa.len: if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)): - if not useLineInfo or gCmd == cmdDoc: return + if not useLineInfo or a.config.cmd == cmdDoc: return elif aa[i].info == e.info: return throws(a.tags, e) @@ -960,7 +960,7 @@ proc trackProc*(g: ModuleGraph; s: PSym, body: PNode) = effects.sons[tagEffects] = tagsSpec if sfThread in s.flags and t.gcUnsafe: - if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions: + if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions: #localError(s.info, "'$1' is not GC-safe" % s.name.s) listGcUnsafety(s, onlyWarning=false, g.config) else: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0a51ccee47..7282ea58cf 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -139,7 +139,7 @@ proc discardCheck(c: PContext, result: PNode) = while n.kind in skipForDiscardable: n = n.lastSon n.typ = nil - elif result.typ.kind != tyError and gCmd != cmdInteractive: + elif result.typ.kind != tyError and c.config.cmd != cmdInteractive: var n = result while n.kind in skipForDiscardable: n = n.lastSon var s = "expression '" & $n & "' is of type '" & @@ -255,7 +255,7 @@ proc semTry(c: PContext, n: PNode): PNode = # returns true if exception type is imported type let typ = semTypeNode(c, typeNode, nil).toObject() var is_imported = false - if isImportedException(typ): + if isImportedException(typ, c.config): is_imported = true elif not isException(typ): localError(c.config, typeNode.info, errExprCannotBeRaised) @@ -398,7 +398,7 @@ proc semUsing(c: PContext; n: PNode): PNode = if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "using") for i in countup(0, sonsLen(n)-1): var a = n.sons[i] - if gCmd == cmdIdeTools: suggestStmt(c, a) + if c.config.cmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config) checkMinSonsLen(a, 3, c.config) @@ -471,7 +471,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var hasCompileTime = false for i in countup(0, sonsLen(n)-1): var a = n.sons[i] - if gCmd == cmdIdeTools: suggestStmt(c, a) + if c.config.cmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config) checkMinSonsLen(a, 3, c.config) @@ -578,7 +578,7 @@ proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if gCmd == cmdIdeTools: suggestStmt(c, a) + if c.config.cmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue if a.kind != nkConstDef: illFormedAst(a, c.config) checkSonsLen(a, 3, c.config) @@ -756,7 +756,7 @@ proc semRaise(c: PContext, n: PNode): PNode = if n[0].kind != nkEmpty: n[0] = semExprWithType(c, n[0]) let typ = n[0].typ - if not isImportedException(typ): + if not isImportedException(typ, c.config): if typ.kind != tyRef or typ.lastSon.kind != tyObject: localError(c.config, n.info, errExprCannotBeRaised) if not isException(typ.lastSon): @@ -785,7 +785,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] when defined(nimsuggest): - if gCmd == cmdIdeTools: + if c.config.cmd == cmdIdeTools: inc c.inTypeContext suggestStmt(c, a) dec c.inTypeContext @@ -1236,7 +1236,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = s.typ = newProcType(c, n.info) if n.sons[pragmasPos].kind != nkEmpty: pragma(c, s, n.sons[pragmasPos], lambdaPragmas) - s.options = gOptions + s.options = c.config.options if n.sons[bodyPos].kind != nkEmpty: if sfImportc in s.flags: localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s) @@ -1565,7 +1565,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, proto.ast = n # needed for code generation popOwner(c) pushOwner(c, s) - s.options = gOptions + s.options = c.config.options if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) if s.name.s[0] in {'.', '('}: if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f44d93f200..52afce688a 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -451,7 +451,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = else: addSon(result.n, newSymNode(field)) addSonSkipIntLit(result, typ) - if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field) + if c.config.cmd == cmdPretty: styleCheckDef(a.sons[j].info, field) if result.n.len == 0: result.n = nil proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, @@ -491,7 +491,7 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, else: discard else: result = semIdentVis(c, kind, n, allowed) - if gCmd == cmdPretty: styleCheckDef(n.info, result) + if c.config.cmd == cmdPretty: styleCheckDef(n.info, result) proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) = let ex = t[branchIndex][currentEx].skipConv @@ -1062,7 +1062,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, addSon(result.n, newSymNode(arg)) rawAddSon(result, finalType) addParamOrResult(c, arg, kind) - if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, arg) + if c.config.cmd == cmdPretty: styleCheckDef(a.sons[j].info, arg) var r: PType if n.sons[0].kind != nkEmpty: @@ -1354,7 +1354,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = nil inc c.inTypeContext - if gCmd == cmdIdeTools: suggestExpr(c, n) + if c.config.cmd == cmdIdeTools: suggestExpr(c, n) case n.kind of nkEmpty: discard of nkTypeOfExpr: diff --git a/compiler/service.nim b/compiler/service.nim index 9b45f7bd71..f1a988ae5e 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -42,7 +42,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) = of cmdArgument: if processArgument(pass, p, argsCount, config): break if pass == passCmd2: - if optRun notin gGlobalOptions and config.arguments.len > 0 and config.command.normalize != "run": + if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run": rawMessage(config, errGenerated, errArgsNeedRunOption) proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; config: ConfigRef) = diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 01413f6788..74c944d516 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -612,7 +612,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags: return isNone elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and - optThreadAnalysis in gGlobalOptions: + optThreadAnalysis in c.c.config.globalOptions: # noSideEffect implies ``tfThread``! return isNone elif f.flags * {tfIterator} != a.flags * {tfIterator}: @@ -686,7 +686,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = if alreadyBound != nil: typ = alreadyBound template paramSym(kind): untyped = - newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info) + newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info, {}) block addTypeParam: for prev in typeParams: diff --git a/compiler/suggest.nim b/compiler/suggest.nim index ba70de1f74..23aecfa71b 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -106,7 +106,7 @@ proc cmpSuggestions(a, b: Suggest): int = # independent of hashing order: result = cmp(a.name.s, b.name.s) -proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; +proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; quality: range[0..100]; prefix: PrefixMatch; inTypeContext: bool; scope: int): Suggest = new(result) @@ -125,7 +125,7 @@ proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; if u.fileIndex == info.fileIndex: inc c result.localUsages = c result.symkind = s.kind - if optIdeTerse notin gGlobalOptions: + if optIdeTerse notin conf.globalOptions: result.qualifiedPath = @[] if not isLocal and s.kind != skModule: let ow = s.owner @@ -237,7 +237,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) = var pm: PrefixMatch if filterSym(s, f, pm) and fieldVisible(c, s): - outputs.add(symToSuggest(s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0)) + outputs.add(symToSuggest(c.config, s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0)) proc getQuality(s: PSym): range[0..100] = if s.typ != nil and s.typ.len > 1: @@ -256,7 +256,7 @@ template wholeSymTab(cond, section: untyped) = let it {.inject.} = item var pm {.inject.}: PrefixMatch if cond: - outputs.add(symToSuggest(it, isLocal = isLocal, section, info, getQuality(it), + outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it), pm, c.inTypeContext > 0, scopeN)) proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) = @@ -330,7 +330,7 @@ proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) = for it in items(scope.symbols): var pm: PrefixMatch if filterSym(it, f, pm): - outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, n.info, 0, pm, + outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, n.info, 0, pm, c.inTypeContext > 0, scopeN)) #if scope == c.topLevelScope and f.isNil: break @@ -352,8 +352,8 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) else: for it in items(n.sym.tab): if filterSym(it, field, pm): - outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100)) - outputs.add(symToSuggest(m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None, + outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100)) + outputs.add(symToSuggest(c.config, m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None, c.inTypeContext > 0, -99)) if typ == nil: @@ -363,11 +363,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) # all symbols accessible, because we are in the current module: for it in items(c.topLevelScope.symbols): if filterSym(it, field, pm): - outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) else: for it in items(n.sym.tab): if filterSym(it, field, pm): - outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) else: # fallback: suggestEverything(c, n, field, outputs) @@ -426,29 +426,29 @@ when defined(nimsuggest): s.allUsages.add(info) var - lastLineInfo*: TLineInfo + lastLineInfo*: TLineInfo # XXX global here -proc findUsages(info: TLineInfo; s: PSym; usageSym: var PSym) = +proc findUsages(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = if suggestVersion == 1: if usageSym == nil and isTracked(info, s.name.s.len): usageSym = s - suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) elif s == usageSym: if lastLineInfo != info: - suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) lastLineInfo = info when defined(nimsuggest): - proc listUsages*(s: PSym) = + proc listUsages*(conf: ConfigRef; s: PSym) = #echo "usages ", len(s.allUsages) for info in s.allUsages: let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse - suggestResult(symToSuggest(s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(conf, s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0)) -proc findDefinition(info: TLineInfo; s: PSym) = +proc findDefinition(conf: ConfigRef; info: TLineInfo; s: PSym) = if s.isNil: return if isTracked(info, s.name.s.len): - suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) suggestQuit() proc ensureIdx[T](x: var T, y: int) = @@ -467,18 +467,18 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; s.addNoDup(info) if conf.ideCmd == ideUse: - findUsages(info, s, usageSym) + findUsages(conf, info, s, usageSym) elif conf.ideCmd == ideDef: - findDefinition(info, s) + findDefinition(conf, info, s) elif conf.ideCmd == ideDus and s != nil: if isTracked(info, s.name.s.len): - suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) - findUsages(info, s, usageSym) + suggestResult(symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) + findUsages(conf, info, s, usageSym) elif conf.ideCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex: - suggestResult(symToSuggest(s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(conf, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) elif conf.ideCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and isDecl: - suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) = if s.kind in routineKinds: @@ -587,7 +587,7 @@ proc suggestSentinel*(c: PContext) = for it in items(scope.symbols): var pm: PrefixMatch if filterSymNoOpr(it, nil, pm): - outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN)) + outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN)) dec(c.compilesContextId) produceOutput(outputs, c.config) diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 4a6474912e..18d68bd2d4 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -119,7 +119,7 @@ proc applyFilter(p: var TParsers, n: PNode, filename: string, if f != filtNone: if hintCodeBegin in p.config.notes: rawMessage(p.config, hintCodeBegin, []) - msgWriteln(result.s) + msgWriteln(p.config, result.s) rawMessage(p.config, hintCodeEnd, []) proc evalPipe(p: var TParsers, n: PNode, filename: string, diff --git a/compiler/transf.nim b/compiler/transf.nim index e49d51b110..a10e8a1e54 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -358,7 +358,7 @@ proc transformYield(c: PTransf, n: PNode): PTransNode = proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = result = transformSons(c, n) - if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return + if c.graph.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return var n = result.PNode case n.sons[0].kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: @@ -390,7 +390,7 @@ proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode = # we cannot generate a proper thunk here for GC-safety reasons # (see internal documentation): - if gCmd == cmdCompileToJS: return prc + if c.graph.config.cmd == cmdCompileToJS: return prc result = newNodeIT(nkClosure, prc.info, dest) var conv = newNodeIT(nkHiddenSubConv, prc.info, dest) conv.add(emptyNode) @@ -716,7 +716,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = proc transformExceptBranch(c: PTransf, n: PNode): PTransNode = result = transformSons(c, n) - if n[0].isInfixAs() and (not isImportedException(n[0][1].typ)): + if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config): let excTypeNode = n[0][1] let actions = newTransNode(nkStmtListExpr, n[1], 2) # Generating `let exc = (excType)(getCurrentException())` From 6ca8478548dba27cb00f640ba0cbae91f35871a9 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Sun, 13 May 2018 21:42:30 -0500 Subject: [PATCH 199/214] Minor fixes to enable tcc --- config/nim.cfg | 2 +- lib/pure/concurrency/threadpool.nim | 2 +- lib/system/atomics.nim | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/nim.cfg b/config/nim.cfg index a2a774b236..9b3172e90a 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -118,7 +118,7 @@ path="$lib/pure" # Configuration for the GNU C/C++ compiler: @if windows: #gcc.path = r"$nim\dist\mingw\bin" - @if gcc: + @if gcc or tcc: tlsEmulation:on @end @end diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index ca4f80f2a4..6ec71e912c 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -331,7 +331,7 @@ proc slave(w: ptr Worker) {.thread.} = await(w.taskArrived) # XXX Somebody needs to look into this (why does this assertion fail # in Visual Studio?) - when not defined(vcc): assert(not w.ready) + when not defined(vcc) and not defined(tcc): assert(not w.ready) withLock numSlavesLock: inc numSlavesRunning diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim index fa3700190e..56ebde823e 100644 --- a/lib/system/atomics.nim +++ b/lib/system/atomics.nim @@ -241,7 +241,7 @@ when defined(vcc): else: {.error: "invalid CAS instruction".} -elif defined(tcc) and not defined(windows): +elif defined(tcc): when defined(amd64): {.emit:""" static int __tcc_cas(int *ptr, int oldVal, int newVal) @@ -262,7 +262,7 @@ static int __tcc_cas(int *ptr, int oldVal, int newVal) } """.} else: - assert sizeof(int) == 4 + #assert sizeof(int) == 4 {.emit:""" static int __tcc_cas(int *ptr, int oldVal, int newVal) { From 5fcfc43a205aa9ccc4da46aeca29f7f7e86a94af Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 10 May 2018 17:23:08 +0100 Subject: [PATCH 200/214] Adds onpopstate and proc related to Events to dom module. --- lib/js/dom.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index cd76097290..541c148669 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -62,6 +62,7 @@ type frames*: seq[TFrame] screen*: Screen performance*: Performance + onpopstate*: proc (event: Event) Frame* = ref FrameObj FrameObj {.importc.} = object of WindowObj @@ -446,6 +447,7 @@ type proc addEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false) proc addEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), options: AddEventListenerOptions) proc removeEventListener*(et: EventTarget, ev: cstring, cb: proc(ev: Event), useCapture: bool = false) +proc dispatchEvent*(et: EventTarget, ev: Event) # Window "methods" proc alert*(w: Window, msg: cstring) @@ -596,6 +598,7 @@ proc parseFloat*(s: cstring): BiggestFloat {.importc, nodecl.} proc parseInt*(s: cstring): int {.importc, nodecl.} proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.} +proc newEvent*(name: cstring): Event {.importcpp: "new Event(@)", constructor.} type TEventHandlers* {.deprecated.} = EventTargetObj From 6b5ad56ab3b5c6f62f8a5f312fe282ff05f7bafa Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 12 May 2018 15:28:37 +0100 Subject: [PATCH 201/214] Adds TextAreaElement type. --- lib/js/dom.nim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 541c148669..fd81fdf3f1 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -176,6 +176,12 @@ type text*: cstring value*: cstring + TextAreaElement* = ref object of ElementObj + value*: cstring + selectionStart*, selectionEnd*: int + selectionDirection*: cstring + rows*, cols*: int + FormElement* = ref FormObj FormObj {.importc.} = object of ElementObj action*: cstring @@ -502,7 +508,7 @@ proc removeAttributeNode*(n, attr: Node) proc removeChild*(n, child: Node) proc replaceChild*(n, newNode, oldNode: Node) proc replaceData*(n: Node, start, len: int, text: cstring) -proc scrollIntoView*(n: Node) +proc scrollIntoView*(n: Node, alignToTop: bool=true) proc setAttribute*(n: Node, name, value: cstring) proc setAttributeNode*(n: Node, attr: Node) From 1616c6e0297efd09000c4286d1fdfc986ee1ab7a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 14 May 2018 13:04:18 +0200 Subject: [PATCH 202/214] make nimsuggest compile again --- nimsuggest/nimsuggest.nim | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index bbb751ba6f..5c505ddf77 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -195,7 +195,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int; if conf.ideCmd in {ideUse, ideDus}: let u = if suggestVersion != 1: graph.symFromInfo(gTrackPos) else: graph.usageSym if u != nil: - listUsages(u) + listUsages(conf, u) else: localError(conf, gTrackPos, "found no symbol at this position " & $gTrackPos) @@ -385,10 +385,10 @@ proc execCmd(cmd: string; graph: ModuleGraph; cache: IdentCache; cachedMsgs: Cac results.send(Suggest(section: ideNone)) template toggle(sw) = - if sw in gGlobalOptions: - excl(gGlobalOptions, sw) + if sw in conf.globalOptions: + excl(conf.globalOptions, sw) else: - incl(gGlobalOptions, sw) + incl(conf.globalOptions, sw) sentinel() return @@ -490,8 +490,8 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) = clearPasses() registerPass verbosePass registerPass semPass - gCmd = cmdIdeTools - incl gGlobalOptions, optCaasEnabled + conf.cmd = cmdIdeTools + incl conf.globalOptions, optCaasEnabled wantMainModule(conf) if not fileExists(conf.projectFull): @@ -546,15 +546,15 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = of "cmdsug": gMode = mcmdsug gAddress = p.val - incl(gGlobalOptions, optIdeDebug) + incl(conf.globalOptions, optIdeDebug) of "cmdcon": gMode = mcmdcon gAddress = p.val - incl(gGlobalOptions, optIdeDebug) + incl(conf.globalOptions, optIdeDebug) of "epc": gMode = mepc - gVerbosity = 0 # Port number gotta be first. - of "debug": incl(gGlobalOptions, optIdeDebug) + conf.verbosity = 0 # Port number gotta be first. + of "debug": incl(conf.globalOptions, optIdeDebug) of "v2": suggestVersion = 0 of "v1": suggestVersion = 1 of "tester": From 02b78d3f94225ab1b204191d0fb199125787f31d Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 14 May 2018 21:38:18 +0200 Subject: [PATCH 203/214] make tests green again --- compiler/parser.nim | 2 +- compiler/semcall.nim | 4 ++-- compiler/seminst.nim | 4 ++-- compiler/sempass2.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/semtypes.nim | 8 ++++---- compiler/semtypinst.nim | 4 ++-- compiler/sigmatch.nim | 4 ++-- compiler/types.nim | 2 +- tests/controlflow/tstatret.nim | 2 +- tests/errmsgs/tinvalidinout.nim | 8 ++++---- tests/lexer/tunderscores.nim | 2 +- tests/misc/tunsignedmisc.nim | 2 +- tests/objvariant/temptycaseobj.nim | 2 +- tests/parser/tinvcolonlocation1.nim | 4 ++-- tests/parser/tinvcolonlocation2.nim | 4 ++-- tests/parser/tinvcolonlocation3.nim | 4 ++-- tests/parser/twhen_in_enum.nim | 2 +- tests/types/tparameterizedparent3.nim | 2 +- tests/types/tparameterizedparent4.nim | 2 +- 20 files changed, 33 insertions(+), 33 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 082dcd9ed1..fbc57ebb66 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -183,7 +183,7 @@ proc eat(p: var TParser, tokType: TTokType) = getTok(p) else: lexMessage(p.lex, errGenerated, - "expected " & TokTypeToStr[tokType] & ", but got: " & prettyTok(p.tok)) + "expected: '" & TokTypeToStr[tokType] & "', but got: '" & prettyTok(p.tok) & "'") proc parLineInfo(p: TParser): TLineInfo = ## Retrieve the line information associated with the parser's current state. diff --git a/compiler/semcall.nim b/compiler/semcall.nim index b4d4cad7e6..e9a31d3d6c 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -507,8 +507,8 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = # number of generic type parameters: if safeLen(s.ast.sons[genericParamsPos]) != n.len-1: let expected = safeLen(s.ast.sons[genericParamsPos]) - localError(c.config, n.info, errGenerated, "cannot instantiate: " & renderTree(n) & - "; got " & $(n.len-1) & " type(s) but expected " & $expected) + localError(c.config, n.info, errGenerated, "cannot instantiate: '" & renderTree(n) & + "'; got " & $(n.len-1) & " type(s) but expected " & $expected) return n result = explicitGenericSym(c, n, s) if result == nil: result = explicitGenericInstError(c, n) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 60c655bba4..a5f0ca7d81 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -74,10 +74,10 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym # later by semAsgn in return type inference scenario t = q.typ else: - localError(c.config, a.info, errCannotInstantiateX & s.name.s) + localError(c.config, a.info, errCannotInstantiateX % s.name.s) t = errorType(c) elif t.kind == tyGenericParam: - localError(c.config, a.info, errCannotInstantiateX & q.name.s) + localError(c.config, a.info, errCannotInstantiateX % q.name.s) t = errorType(c) elif t.kind == tyGenericInvocation: #t = instGenericContainer(c, a, t) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 5431615242..b66d7d9f2a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -970,7 +970,7 @@ proc trackProc*(g: ModuleGraph; s: PSym, body: PNode) = when false: listGcUnsafety(s, onlyWarning=false, g.config) else: - localError(g.config, s.info, "'$1' has side effects" % s.name.s) + localError(g.config, s.info, "'$1' can have side effects" % s.name.s) if not t.gcUnsafe: s.typ.flags.incl tfGcSafe if not t.hasSideEffect and sfSideEffect notin s.flags: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 2d4b5ae778..3687e50e9c 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -233,7 +233,7 @@ proc semCase(c: PContext, n: PNode): PNode = if covered == toCover(n.sons[0].typ): hasElse = true else: - localError(c.config, n.info, "not all cases covered") + localError(c.config, n.info, "not all cases are covered") closeScope(c) if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 52afce688a..8b5c26f99b 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -447,7 +447,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = field.position = counter inc(counter) if containsOrIncl(check, field.name.id): - localError(c.config, a.sons[j].info, "attempt to redefine: " & field.name.s) + localError(c.config, a.sons[j].info, "attempt to redefine: '" & field.name.s & "'") else: addSon(result.n, newSymNode(field)) addSonSkipIntLit(result, typ) @@ -682,7 +682,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, f.flags = f.flags + ({sfImportc, sfExportc} * fieldOwner.flags) inc(pos) if containsOrIncl(check, f.name.id): - localError(c.config, n.sons[i].info, "attempt to redefine: " & f.name.s) + localError(c.config, n.sons[i].info, "attempt to redefine: '" & f.name.s & "'") if a.kind == nkEmpty: addSon(father, newSymNode(f)) else: addSon(a, newSymNode(f)) styleCheckDef(f) @@ -692,7 +692,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, # inherited from generic/partial specialized parent second check. # There is no branch validity check here if containsOrIncl(check, n.sym.name.id): - localError(c.config, n.info, "attempt to redefine: " & n.sym.name.s) + localError(c.config, n.info, "attempt to redefine: '" & n.sym.name.s & "'") addSon(father, n) of nkEmpty: discard else: illFormedAst(n, c.config) @@ -1058,7 +1058,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, inc(counter) if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def) if containsOrIncl(check, arg.name.id): - localError(c.config, a.sons[j].info, "attempt to redefine: " & arg.name.s) + localError(c.config, a.sons[j].info, "attempt to redefine: '" & arg.name.s & "'") addSon(result.n, newSymNode(arg)) rawAddSon(result, finalType) addParamOrResult(c, arg, kind) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 4fdc743733..61d92bb196 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -243,7 +243,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = result = cl.typeMap.lookup(t) if result == nil: if cl.allowMetaTypes or tfRetType in t.flags: return - localError(cl.c.config, t.sym.info, "cannot instantiate: " & typeToString(t)) + localError(cl.c.config, t.sym.info, "cannot instantiate: '" & typeToString(t) & "'") result = errorType(cl.c) # In order to prevent endless recursions, we must remember # this bad lookup and replace it with errorType everywhere. @@ -453,7 +453,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result.kind = tyUserTypeClassInst of tyGenericBody: - localError(cl.c.config, cl.info, "cannot instantiate: " & typeToString(t)) + localError(cl.c.config, cl.info, "cannot instantiate: '" & typeToString(t) & "'") result = errorType(cl.c) #result = replaceTypeVarsT(cl, lastSon(t)) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 1d4515875d..41cac2a4af 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2365,7 +2365,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; var m: TCandidate initCandidate(c, m, dc.typ) if col >= dc.typ.len: - localError(c.config, info, "cannot instantiate '" & dc.name.s & "'") + localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'") return nil var f = dc.typ.sons[col] @@ -2374,7 +2374,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; else: if f.kind == tyVar: f = f.lastSon if typeRel(m, f, t) == isNone: - localError(c.config, info, "cannot instantiate '" & dc.name.s & "'") + localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'") else: result = c.semGenerateInstance(c, dc, m.bindings, info) if op == attachedDeepCopy: diff --git a/compiler/types.nim b/compiler/types.nim index 9c2ad71c5a..b5f4fbf54d 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1640,7 +1640,7 @@ proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType) = let x = if named == desc: named else: named & " = " & desc var msg = "type mismatch: got <" & typeToString(actual) & "> " & - "but expected " & x & "'" + "but expected '" & x & "'" if formal.kind == tyProc and actual.kind == tyProc: case compatibleEffects(formal, actual) diff --git a/tests/controlflow/tstatret.nim b/tests/controlflow/tstatret.nim index d655f55953..04cac99665 100644 --- a/tests/controlflow/tstatret.nim +++ b/tests/controlflow/tstatret.nim @@ -1,7 +1,7 @@ discard """ file: "tstatret.nim" line: 9 - errormsg: "statement not allowed after" + errormsg: "unreachable statement after 'return'" """ # no statement after return proc main() = diff --git a/tests/errmsgs/tinvalidinout.nim b/tests/errmsgs/tinvalidinout.nim index ce7eb6022c..1fa3805ee7 100644 --- a/tests/errmsgs/tinvalidinout.nim +++ b/tests/errmsgs/tinvalidinout.nim @@ -1,10 +1,10 @@ discard """ cmd: "nim check $file" -errormsg: "The `in` modifier can be used only with imported types" +errormsg: "the 'in' modifier can be used only with imported types" nimout: ''' -tinvalidinout.nim(14, 7) Error: The `out` modifier can be used only with imported types -tinvalidinout.nim(17, 9) Error: The `in` modifier can be used only with imported types -tinvalidinout.nim(18, 9) Error: The `in` modifier can be used only with imported types +tinvalidinout.nim(14, 7) Error: the 'out' modifier can be used only with imported types +tinvalidinout.nim(17, 9) Error: the 'in' modifier can be used only with imported types +tinvalidinout.nim(18, 9) Error: the 'in' modifier can be used only with imported types ''' """ diff --git a/tests/lexer/tunderscores.nim b/tests/lexer/tunderscores.nim index e718fb40ae..f64f369773 100644 --- a/tests/lexer/tunderscores.nim +++ b/tests/lexer/tunderscores.nim @@ -1,7 +1,7 @@ discard """ file: "tunderscores.nim" line: 8 - errormsg: "invalid token: _" + errormsg: "invalid token: trailing underscore" """ # Bug #502670 diff --git a/tests/misc/tunsignedmisc.nim b/tests/misc/tunsignedmisc.nim index 4b8157dddb..fc02eee195 100644 --- a/tests/misc/tunsignedmisc.nim +++ b/tests/misc/tunsignedmisc.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "number 0x123'u8 out of valid range" + errormsg: "number out of range: '0x123'u8'" """ # Bug #1179 diff --git a/tests/objvariant/temptycaseobj.nim b/tests/objvariant/temptycaseobj.nim index 5c012746ec..53171e054c 100644 --- a/tests/objvariant/temptycaseobj.nim +++ b/tests/objvariant/temptycaseobj.nim @@ -1,6 +1,6 @@ discard """ line: 11 - errormsg: "identifier expected, but found 'keyword of'" + errormsg: "identifier expected, but got 'keyword of'" """ type diff --git a/tests/parser/tinvcolonlocation1.nim b/tests/parser/tinvcolonlocation1.nim index cacde48bd7..2fddab2f87 100644 --- a/tests/parser/tinvcolonlocation1.nim +++ b/tests/parser/tinvcolonlocation1.nim @@ -1,8 +1,8 @@ discard """ file: "tinvcolonlocation1.nim" line: 8 - column: 3 - errormsg: "':' expected" + column: 7 + errormsg: "expected: ':', but got: 'echo'" """ try #<- missing ':' echo "try" diff --git a/tests/parser/tinvcolonlocation2.nim b/tests/parser/tinvcolonlocation2.nim index 2b6a92b9d8..4251598b99 100644 --- a/tests/parser/tinvcolonlocation2.nim +++ b/tests/parser/tinvcolonlocation2.nim @@ -1,8 +1,8 @@ discard """ file: "tinvcolonlocation2.nim" line: 11 - column: 1 - errormsg: "':' expected" + column: 8 + errormsg: "expected: ':', but got: 'keyword finally'" """ try: echo "try" diff --git a/tests/parser/tinvcolonlocation3.nim b/tests/parser/tinvcolonlocation3.nim index 2b30b1dbe9..a8db658eb4 100644 --- a/tests/parser/tinvcolonlocation3.nim +++ b/tests/parser/tinvcolonlocation3.nim @@ -1,8 +1,8 @@ discard """ file: "tinvcolonlocation3.nim" line: 12 - column: 3 - errormsg: "':' expected" + column: 7 + errormsg: "expected: ':', but got: 'echo'" """ try: echo "try" diff --git a/tests/parser/twhen_in_enum.nim b/tests/parser/twhen_in_enum.nim index d4a3ea56ac..3890b686ee 100644 --- a/tests/parser/twhen_in_enum.nim +++ b/tests/parser/twhen_in_enum.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "identifier expected, but found 'keyword when'" + errormsg: "identifier expected, but got 'keyword when'" """ # bug #2123 diff --git a/tests/types/tparameterizedparent3.nim b/tests/types/tparameterizedparent3.nim index 3fc83cb4da..58aaf80eae 100644 --- a/tests/types/tparameterizedparent3.nim +++ b/tests/types/tparameterizedparent3.nim @@ -1,7 +1,7 @@ discard """ file: "tparameterizedparent3.nim" line: 13 - errormsg: "redefinition of 'color'" + errormsg: "attempt to redefine: 'color'" """ # bug #5264 type diff --git a/tests/types/tparameterizedparent4.nim b/tests/types/tparameterizedparent4.nim index fa8b525c1f..a37461bb43 100644 --- a/tests/types/tparameterizedparent4.nim +++ b/tests/types/tparameterizedparent4.nim @@ -1,7 +1,7 @@ discard """ file: "tparameterizedparent4.nim" line: 23 - errormsg: "redefinition of 'grain'" + errormsg: "attempt to redefine: 'grain'" """ # bug #5264 type From f8e23daa201abc83e3e4761621d20bb7dfe974c3 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 14 May 2018 23:27:44 +0200 Subject: [PATCH 204/214] fixes #7817 --- lib/pure/json.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index b16918959c..9f93399617 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -832,6 +832,9 @@ proc toJson(x: NimNode): NimNode {.compiletime.} = result = newCall(bindSym"newJObject") of nnkNilLit: result = newCall(bindSym"newJNull") + of nnkPar: + if x.len == 1: result = toJson(x[0]) + else: result = newCall(bindSym"%", x) else: result = newCall(bindSym"%", x) From 5bf6ad9fa3a51e57ea7c0f9abb9d31e83cb140cf Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 15 May 2018 01:39:56 +0200 Subject: [PATCH 205/214] make tests green on Unix --- compiler/msgs.nim | 4 ---- compiler/options.nim | 7 ++++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 774a8b83ca..533d3a57f0 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -647,7 +647,3 @@ proc listHints*(conf: ConfigRef) = if hint in conf.notes: "x" else: " ", configuration.HintsToStr[ord(hint) - ord(hintMin)] ]) - -# enable colors by default on terminals -#if terminal.isatty(stderr): -# incl(gGlobalOptions, optUseColors) diff --git a/compiler/options.nim b/compiler/options.nim index 56c3dcf0b7..2027897fa4 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -10,6 +10,8 @@ import os, strutils, strtabs, osproc, sets, configuration, platform +from terminal import isatty + const hasTinyCBackend* = defined(tinyc) useEffectSystem* = true @@ -182,7 +184,7 @@ const optBoundsCheck, optOverflowCheck, optAssert, optWarns, optHints, optStackTrace, optLineTrace, optPatterns, optNilCheck, optMoveCheck} - DefaultGlobalOptions* = {optThreadAnalysis, optUseColors} + DefaultGlobalOptions* = {optThreadAnalysis} template newPackageCache*(): untyped = newStringTable(when FileSystemCaseSensitive: @@ -221,6 +223,9 @@ proc newConfigRef*(): ConfigRef = implicitIncludes: @[], # modules that are to be implicitly included docSeeSrcUrl: "" ) + # enable colors by default on terminals + if terminal.isatty(stderr): + incl(result.globalOptions, optUseColors) proc newPartialConfigRef*(): ConfigRef = ## create a new ConfigRef that is only good enough for error reporting. From c73cd5349ef532e8ac323a05c98fab7cb5c12fa5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 15 May 2018 10:03:06 +0200 Subject: [PATCH 206/214] documentation generator works again --- compiler/main.nim | 16 ++++++++-------- compiler/nimconf.nim | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index 69b33653bc..e3f00db9ef 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -188,43 +188,43 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = of "doc0": wantMainModule(conf) conf.cmd = cmdDoc - loadConfigs(DocConfig, cache) + loadConfigs(DocConfig, cache, conf) commandDoc(conf) of "doc2", "doc": conf.cmd = cmdDoc - loadConfigs(DocConfig, cache) + loadConfigs(DocConfig, cache, conf) defineSymbol(conf.symbols, "nimdoc") commandDoc2(graph, cache, false) of "rst2html": conf.cmd = cmdRst2html - loadConfigs(DocConfig, cache) + loadConfigs(DocConfig, cache, conf) commandRst2Html(conf) of "rst2tex": conf.cmd = cmdRst2tex - loadConfigs(DocTexConfig, cache) + loadConfigs(DocTexConfig, cache, conf) commandRst2TeX(conf) of "jsondoc0": wantMainModule(conf) conf.cmd = cmdDoc - loadConfigs(DocConfig, cache) + loadConfigs(DocConfig, cache, conf) wantMainModule(conf) defineSymbol(conf.symbols, "nimdoc") commandJson(conf) of "jsondoc2", "jsondoc": conf.cmd = cmdDoc - loadConfigs(DocConfig, cache) + loadConfigs(DocConfig, cache, conf) wantMainModule(conf) defineSymbol(conf.symbols, "nimdoc") commandDoc2(graph, cache, true) of "ctags": wantMainModule(conf) conf.cmd = cmdDoc - loadConfigs(DocConfig, cache) + loadConfigs(DocConfig, cache, conf) defineSymbol(conf.symbols, "nimdoc") commandTags(conf) of "buildindex": conf.cmd = cmdDoc - loadConfigs(DocConfig, cache) + loadConfigs(DocConfig, cache, conf) commandBuildIndex(conf) of "gendepend": conf.cmd = cmdGenDepend diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 379d15ad68..6cb5bab0fb 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -230,7 +230,7 @@ proc getSystemConfigPath(conf: ConfigRef; filename: string): string = if not existsFile(result): result = joinPath([p, "etc", filename]) if not existsFile(result): result = "/etc/" & filename -proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef = nil) = +proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) = setDefaultLibpath(conf) if optSkipConfigFile notin conf.globalOptions: From 6c0185d4b7a9b38fa246c47c6d9baf3633e880d0 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 16 May 2018 13:04:08 +0300 Subject: [PATCH 207/214] Allow better optimisations by removing NOINLINE from module init procs --- compiler/cgen.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 133e86cea5..79bcf04910 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1115,8 +1115,8 @@ proc registerModuleToMain(g: BModuleList; m: PSym) = var init = m.getInitName datInit = m.getDatInitName - addf(g.mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init]) - addf(g.mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit]) + addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) + addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit]) if sfSystemModule notin m.flags: addf(g.mainDatInit, "\t$1();$N", [datInit]) let initCall = "\t$1();$N" % [init] @@ -1127,7 +1127,7 @@ proc registerModuleToMain(g: BModuleList; m: PSym) = proc genInitCode(m: BModule) = var initname = getInitName(m.module) - var prc = "NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N" % [initname] + var prc = "N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N" % [initname] if m.typeNodes > 0: appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", [m.typeNodesName, rope(m.typeNodes)]) @@ -1169,7 +1169,7 @@ proc genInitCode(m: BModule) = add(prc, deinitGCFrame(m.initProc)) addf(prc, "}$N$N", []) - prc.addf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", + prc.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N", [getDatInitName(m.module)]) for i in cfsTypeInit1..cfsDynLibInit: From 173c92d374323f6fbbecae2ac344e6062dcfa351 Mon Sep 17 00:00:00 2001 From: data-man Date: Thu, 17 May 2018 19:54:41 +0300 Subject: [PATCH 208/214] Fixes factorial's bug --- lib/pure/math.nim | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 5f3240e000..9e590debc2 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -41,7 +41,7 @@ proc fac*(n: int): int = createFactTable[13]() else: createFactTable[21]() - assert(n > 0, $n & " must not be negative.") + assert(n >= 0, $n & " must not be negative.") assert(n < factTable.len, $n & " is too large to look up in the table") factTable[n] @@ -560,3 +560,14 @@ when isMainModule: assert sgn(Inf) == 1 assert sgn(NaN) == 0 + block: # fac() tests + try: + discard fac(-1) + except AssertionError: + discard + + doAssert fac(0) == 1 + doAssert fac(1) == 1 + doAssert fac(2) == 2 + doAssert fac(3) == 6 + doAssert fac(4) == 24 From 4b3ad4f00cf8b5080c38248e32d3de27badb4101 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 18 May 2018 01:35:09 +0200 Subject: [PATCH 209/214] keep algorithm.nim warning free --- lib/pure/algorithm.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 22793ab1c9..2b668d1ca6 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -520,15 +520,15 @@ when isMainModule: block testBinarySearch: var noData: seq[int] - doAssert binarySearch(noData, 7) == -1 + doAssert binarySearch(noData, 7) == -1 let oneData = @[1] - doAssert binarySearch(oneData, 1) == 0 - doAssert binarySearch(onedata, 7) == -1 + doAssert binarySearch(oneData, 1) == 0 + doAssert binarySearch(onedata, 7) == -1 let someData = @[1,3,4,7] - doAssert binarySearch(someData, 1) == 0 - doAssert binarySearch(somedata, 7) == 3 + doAssert binarySearch(someData, 1) == 0 + doAssert binarySearch(somedata, 7) == 3 doAssert binarySearch(someData, -1) == -1 - doAssert binarySearch(someData, 5) == -1 + doAssert binarySearch(someData, 5) == -1 doAssert binarySearch(someData, 13) == -1 let moreData = @[1,3,5,7,4711] doAssert binarySearch(moreData, -1) == -1 From 4e63f0c267c43821b7d471c8bb56f21c5d5b6d6f Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 18 May 2018 01:35:53 +0200 Subject: [PATCH 210/214] keep unicode.nim warning free --- lib/pure/unicode.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index cc4d28f5ba..bfd01be550 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -1826,8 +1826,8 @@ when isMainModule: doAssert(runeSubStr(s, 17, 1) == "€") # echo runeStrAtPos(s, 18) # index error - doAssert(runeSubStr(s, 0) == "Hänsel ««: 10,00€") - doAssert(runeSubStr(s, -18) == "Hänsel ««: 10,00€") + doAssert(runeSubStr(s, 0) == "Hänsel ««: 10,00€") + doAssert(runeSubStr(s, -18) == "Hänsel ««: 10,00€") doAssert(runeSubStr(s, 10) == ": 10,00€") doAssert(runeSubStr(s, 18) == "") doAssert(runeSubStr(s, 0, 10) == "Hänsel ««") @@ -1840,7 +1840,7 @@ when isMainModule: doAssert(runeSubStr(s, -6, 5) == "10,00") doAssert(runeSubStr(s, -6, -1) == "10,00") - doAssert(runeSubStr(s, 0, 100) == "Hänsel ««: 10,00€") - doAssert(runeSubStr(s, -100, 100) == "Hänsel ««: 10,00€") + doAssert(runeSubStr(s, 0, 100) == "Hänsel ««: 10,00€") + doAssert(runeSubStr(s, -100, 100) == "Hänsel ««: 10,00€") doAssert(runeSubStr(s, 0, -100) == "") doAssert(runeSubStr(s, 100, -100) == "") From 221b34ad8313be854a6e27352ce67ffe8492b7ff Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 18 May 2018 01:49:49 +0200 Subject: [PATCH 211/214] move parsejson logic into its own standard lib module --- lib/pure/json.nim | 517 +-------------------------------------- lib/pure/parsejson.nim | 535 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 547 insertions(+), 505 deletions(-) create mode 100644 lib/pure/parsejson.nim diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 9f93399617..ca7e164b88 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -89,506 +89,21 @@ ## echo j2 import - hashes, tables, strutils, lexbase, streams, unicode, macros + hashes, tables, strutils, lexbase, streams, unicode, macros, parsejson export tables.`$` +export + parsejson.JsonEventKind, parsejson.JsonError, JsonParser, JsonKindError, + open, close, str, getInt, getFloat, kind, getColumn, getLine, getFilename, + errorMsg, errorMsgExpected, next, JsonParsingError, raiseParseErr + when defined(nimJsonGet): {.pragma: deprecatedGet, deprecated.} else: {.pragma: deprecatedGet.} -type - JsonEventKind* = enum ## enumeration of all events that may occur when parsing - jsonError, ## an error occurred during parsing - jsonEof, ## end of file reached - jsonString, ## a string literal - jsonInt, ## an integer literal - jsonFloat, ## a float literal - jsonTrue, ## the value ``true`` - jsonFalse, ## the value ``false`` - jsonNull, ## the value ``null`` - jsonObjectStart, ## start of an object: the ``{`` token - jsonObjectEnd, ## end of an object: the ``}`` token - jsonArrayStart, ## start of an array: the ``[`` token - jsonArrayEnd ## start of an array: the ``]`` token - - TokKind = enum # must be synchronized with TJsonEventKind! - tkError, - tkEof, - tkString, - tkInt, - tkFloat, - tkTrue, - tkFalse, - tkNull, - tkCurlyLe, - tkCurlyRi, - tkBracketLe, - tkBracketRi, - tkColon, - tkComma - - JsonError* = enum ## enumeration that lists all errors that can occur - errNone, ## no error - errInvalidToken, ## invalid token - errStringExpected, ## string expected - errColonExpected, ## ``:`` expected - errCommaExpected, ## ``,`` expected - errBracketRiExpected, ## ``]`` expected - errCurlyRiExpected, ## ``}`` expected - errQuoteExpected, ## ``"`` or ``'`` expected - errEOC_Expected, ## ``*/`` expected - errEofExpected, ## EOF expected - errExprExpected ## expr expected - - ParserState = enum - stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma, - stateExpectObjectComma, stateExpectColon, stateExpectValue - - JsonParser* = object of BaseLexer ## the parser object. - a: string - tok: TokKind - kind: JsonEventKind - err: JsonError - state: seq[ParserState] - filename: string - - JsonKindError* = object of ValueError ## raised by the ``to`` macro if the - ## JSON kind is incorrect. - -const - errorMessages: array[JsonError, string] = [ - "no error", - "invalid token", - "string expected", - "':' expected", - "',' expected", - "']' expected", - "'}' expected", - "'\"' or \"'\" expected", - "'*/' expected", - "EOF expected", - "expression expected" - ] - tokToStr: array[TokKind, string] = [ - "invalid token", - "EOF", - "string literal", - "int literal", - "float literal", - "true", - "false", - "null", - "{", "}", "[", "]", ":", "," - ] - -proc open*(my: var JsonParser, input: Stream, filename: string) = - ## initializes the parser with an input stream. `Filename` is only used - ## for nice error messages. - lexbase.open(my, input) - my.filename = filename - my.state = @[stateStart] - my.kind = jsonError - my.a = "" - -proc close*(my: var JsonParser) {.inline.} = - ## closes the parser `my` and its associated input stream. - lexbase.close(my) - -proc str*(my: JsonParser): string {.inline.} = - ## returns the character data for the events: ``jsonInt``, ``jsonFloat``, - ## ``jsonString`` - assert(my.kind in {jsonInt, jsonFloat, jsonString}) - return my.a - -proc getInt*(my: JsonParser): BiggestInt {.inline.} = - ## returns the number for the event: ``jsonInt`` - assert(my.kind == jsonInt) - return parseBiggestInt(my.a) - -proc getFloat*(my: JsonParser): float {.inline.} = - ## returns the number for the event: ``jsonFloat`` - assert(my.kind == jsonFloat) - return parseFloat(my.a) - -proc kind*(my: JsonParser): JsonEventKind {.inline.} = - ## returns the current event type for the JSON parser - return my.kind - -proc getColumn*(my: JsonParser): int {.inline.} = - ## get the current column the parser has arrived at. - result = getColNumber(my, my.bufpos) - -proc getLine*(my: JsonParser): int {.inline.} = - ## get the current line the parser has arrived at. - result = my.lineNumber - -proc getFilename*(my: JsonParser): string {.inline.} = - ## get the filename of the file that the parser processes. - result = my.filename - -proc errorMsg*(my: JsonParser): string = - ## returns a helpful error message for the event ``jsonError`` - assert(my.kind == jsonError) - result = "$1($2, $3) Error: $4" % [ - my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]] - -proc errorMsgExpected*(my: JsonParser, e: string): string = - ## returns an error message "`e` expected" in the same format as the - ## other error messages - result = "$1($2, $3) Error: $4" % [ - my.filename, $getLine(my), $getColumn(my), e & " expected"] - -proc handleHexChar(c: char, x: var int): bool = - result = true # Success - case c - of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) - of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) - of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) - else: result = false # error - -proc parseEscapedUTF16(buf: cstring, pos: var int): int = - result = 0 - #UTF-16 escape is always 4 bytes. - for _ in 0..3: - if handleHexChar(buf[pos], result): - inc(pos) - else: - return -1 - -proc parseString(my: var JsonParser): TokKind = - result = tkString - var pos = my.bufpos + 1 - var buf = my.buf - while true: - case buf[pos] - of '\0': - my.err = errQuoteExpected - result = tkError - break - of '"': - inc(pos) - break - of '\\': - case buf[pos+1] - of '\\', '"', '\'', '/': - add(my.a, buf[pos+1]) - inc(pos, 2) - of 'b': - add(my.a, '\b') - inc(pos, 2) - of 'f': - add(my.a, '\f') - inc(pos, 2) - of 'n': - add(my.a, '\L') - inc(pos, 2) - of 'r': - add(my.a, '\C') - inc(pos, 2) - of 't': - add(my.a, '\t') - inc(pos, 2) - of 'u': - inc(pos, 2) - var r = parseEscapedUTF16(buf, pos) - if r < 0: - my.err = errInvalidToken - break - # Deal with surrogates - if (r and 0xfc00) == 0xd800: - if buf[pos] & buf[pos+1] != "\\u": - my.err = errInvalidToken - break - inc(pos, 2) - var s = parseEscapedUTF16(buf, pos) - if (s and 0xfc00) == 0xdc00 and s > 0: - r = 0x10000 + (((r - 0xd800) shl 10) or (s - 0xdc00)) - else: - my.err = errInvalidToken - break - add(my.a, toUTF8(Rune(r))) - else: - # don't bother with the error - add(my.a, buf[pos]) - inc(pos) - of '\c': - pos = lexbase.handleCR(my, pos) - buf = my.buf - add(my.a, '\c') - of '\L': - pos = lexbase.handleLF(my, pos) - buf = my.buf - add(my.a, '\L') - else: - add(my.a, buf[pos]) - inc(pos) - my.bufpos = pos # store back - -proc skip(my: var JsonParser) = - var pos = my.bufpos - var buf = my.buf - while true: - case buf[pos] - of '/': - if buf[pos+1] == '/': - # skip line comment: - inc(pos, 2) - while true: - case buf[pos] - of '\0': - break - of '\c': - pos = lexbase.handleCR(my, pos) - buf = my.buf - break - of '\L': - pos = lexbase.handleLF(my, pos) - buf = my.buf - break - else: - inc(pos) - elif buf[pos+1] == '*': - # skip long comment: - inc(pos, 2) - while true: - case buf[pos] - of '\0': - my.err = errEOC_Expected - break - of '\c': - pos = lexbase.handleCR(my, pos) - buf = my.buf - of '\L': - pos = lexbase.handleLF(my, pos) - buf = my.buf - of '*': - inc(pos) - if buf[pos] == '/': - inc(pos) - break - else: - inc(pos) - else: - break - of ' ', '\t': - inc(pos) - of '\c': - pos = lexbase.handleCR(my, pos) - buf = my.buf - of '\L': - pos = lexbase.handleLF(my, pos) - buf = my.buf - else: - break - my.bufpos = pos - -proc parseNumber(my: var JsonParser) = - var pos = my.bufpos - var buf = my.buf - if buf[pos] == '-': - add(my.a, '-') - inc(pos) - if buf[pos] == '.': - add(my.a, "0.") - inc(pos) - else: - while buf[pos] in Digits: - add(my.a, buf[pos]) - inc(pos) - if buf[pos] == '.': - add(my.a, '.') - inc(pos) - # digits after the dot: - while buf[pos] in Digits: - add(my.a, buf[pos]) - inc(pos) - if buf[pos] in {'E', 'e'}: - add(my.a, buf[pos]) - inc(pos) - if buf[pos] in {'+', '-'}: - add(my.a, buf[pos]) - inc(pos) - while buf[pos] in Digits: - add(my.a, buf[pos]) - inc(pos) - my.bufpos = pos - -proc parseName(my: var JsonParser) = - var pos = my.bufpos - var buf = my.buf - if buf[pos] in IdentStartChars: - while buf[pos] in IdentChars: - add(my.a, buf[pos]) - inc(pos) - my.bufpos = pos - -proc getTok(my: var JsonParser): TokKind = - setLen(my.a, 0) - skip(my) # skip whitespace, comments - case my.buf[my.bufpos] - of '-', '.', '0'..'9': - parseNumber(my) - if {'.', 'e', 'E'} in my.a: - result = tkFloat - else: - result = tkInt - of '"': - result = parseString(my) - of '[': - inc(my.bufpos) - result = tkBracketLe - of '{': - inc(my.bufpos) - result = tkCurlyLe - of ']': - inc(my.bufpos) - result = tkBracketRi - of '}': - inc(my.bufpos) - result = tkCurlyRi - of ',': - inc(my.bufpos) - result = tkComma - of ':': - inc(my.bufpos) - result = tkColon - of '\0': - result = tkEof - of 'a'..'z', 'A'..'Z', '_': - parseName(my) - case my.a - of "null": result = tkNull - of "true": result = tkTrue - of "false": result = tkFalse - else: result = tkError - else: - inc(my.bufpos) - result = tkError - my.tok = result - -proc next*(my: var JsonParser) = - ## retrieves the first/next event. This controls the parser. - var tk = getTok(my) - var i = my.state.len-1 - # the following code is a state machine. If we had proper coroutines, - # the code could be much simpler. - case my.state[i] - of stateEof: - if tk == tkEof: - my.kind = jsonEof - else: - my.kind = jsonError - my.err = errEofExpected - of stateStart: - # tokens allowed? - case tk - of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: - my.state[i] = stateEof # expect EOF next! - my.kind = JsonEventKind(ord(tk)) - of tkBracketLe: - my.state.add(stateArray) # we expect any - my.kind = jsonArrayStart - of tkCurlyLe: - my.state.add(stateObject) - my.kind = jsonObjectStart - of tkEof: - my.kind = jsonEof - else: - my.kind = jsonError - my.err = errEofExpected - of stateObject: - case tk - of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: - my.state.add(stateExpectColon) - my.kind = JsonEventKind(ord(tk)) - of tkBracketLe: - my.state.add(stateExpectColon) - my.state.add(stateArray) - my.kind = jsonArrayStart - of tkCurlyLe: - my.state.add(stateExpectColon) - my.state.add(stateObject) - my.kind = jsonObjectStart - of tkCurlyRi: - my.kind = jsonObjectEnd - discard my.state.pop() - else: - my.kind = jsonError - my.err = errCurlyRiExpected - of stateArray: - case tk - of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: - my.state.add(stateExpectArrayComma) # expect value next! - my.kind = JsonEventKind(ord(tk)) - of tkBracketLe: - my.state.add(stateExpectArrayComma) - my.state.add(stateArray) - my.kind = jsonArrayStart - of tkCurlyLe: - my.state.add(stateExpectArrayComma) - my.state.add(stateObject) - my.kind = jsonObjectStart - of tkBracketRi: - my.kind = jsonArrayEnd - discard my.state.pop() - else: - my.kind = jsonError - my.err = errBracketRiExpected - of stateExpectArrayComma: - case tk - of tkComma: - discard my.state.pop() - next(my) - of tkBracketRi: - my.kind = jsonArrayEnd - discard my.state.pop() # pop stateExpectArrayComma - discard my.state.pop() # pop stateArray - else: - my.kind = jsonError - my.err = errBracketRiExpected - of stateExpectObjectComma: - case tk - of tkComma: - discard my.state.pop() - next(my) - of tkCurlyRi: - my.kind = jsonObjectEnd - discard my.state.pop() # pop stateExpectObjectComma - discard my.state.pop() # pop stateObject - else: - my.kind = jsonError - my.err = errCurlyRiExpected - of stateExpectColon: - case tk - of tkColon: - my.state[i] = stateExpectValue - next(my) - else: - my.kind = jsonError - my.err = errColonExpected - of stateExpectValue: - case tk - of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: - my.state[i] = stateExpectObjectComma - my.kind = JsonEventKind(ord(tk)) - of tkBracketLe: - my.state[i] = stateExpectObjectComma - my.state.add(stateArray) - my.kind = jsonArrayStart - of tkCurlyLe: - my.state[i] = stateExpectObjectComma - my.state.add(stateObject) - my.kind = jsonObjectStart - else: - my.kind = jsonError - my.err = errExprExpected - - -# ------------- higher level interface --------------------------------------- - type JsonNodeKind* = enum ## possible JSON node types JNull, @@ -617,12 +132,6 @@ type of JArray: elems*: seq[JsonNode] - JsonParsingError* = object of ValueError ## is raised for a JSON error - -proc raiseParseErr*(p: JsonParser, msg: string) {.noinline, noreturn.} = - ## raises an `EJsonParsingError` exception. - raise newException(JsonParsingError, errorMsgExpected(p, msg)) - proc newJString*(s: string): JsonNode = ## Creates a new `JString JsonNode`. new(result) @@ -1194,10 +703,6 @@ iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] = for key, val in mpairs(node.fields): yield (key, val) -proc eat(p: var JsonParser, tok: TokKind) = - if p.tok == tok: discard getTok(p) - else: raiseParseErr(p, tokToStr[tok]) - proc parseJson(p: var JsonParser): JsonNode = ## Parses JSON from a JSON Parser `p`. case p.tok @@ -1253,10 +758,12 @@ when not defined(js): ## If `s` contains extra data, it will raise `JsonParsingError`. var p: JsonParser p.open(s, filename) - defer: p.close() - discard getTok(p) # read first token - result = p.parseJson() - eat(p, tkEof) # check if there is no extra data + try: + discard getTok(p) # read first token + result = p.parseJson() + eat(p, tkEof) # check if there is no extra data + finally: + p.close() proc parseJson*(buffer: string): JsonNode = ## Parses JSON from `buffer`. diff --git a/lib/pure/parsejson.nim b/lib/pure/parsejson.nim new file mode 100644 index 0000000000..9c53af6a6c --- /dev/null +++ b/lib/pure/parsejson.nim @@ -0,0 +1,535 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2018 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a json parser. It is used +## and exported by the ``json`` standard library +## module, but can also be used in its own right. + +import + strutils, lexbase, streams, unicode + +type + JsonEventKind* = enum ## enumeration of all events that may occur when parsing + jsonError, ## an error occurred during parsing + jsonEof, ## end of file reached + jsonString, ## a string literal + jsonInt, ## an integer literal + jsonFloat, ## a float literal + jsonTrue, ## the value ``true`` + jsonFalse, ## the value ``false`` + jsonNull, ## the value ``null`` + jsonObjectStart, ## start of an object: the ``{`` token + jsonObjectEnd, ## end of an object: the ``}`` token + jsonArrayStart, ## start of an array: the ``[`` token + jsonArrayEnd ## start of an array: the ``]`` token + + TokKind* = enum # must be synchronized with TJsonEventKind! + tkError, + tkEof, + tkString, + tkInt, + tkFloat, + tkTrue, + tkFalse, + tkNull, + tkCurlyLe, + tkCurlyRi, + tkBracketLe, + tkBracketRi, + tkColon, + tkComma + + JsonError* = enum ## enumeration that lists all errors that can occur + errNone, ## no error + errInvalidToken, ## invalid token + errStringExpected, ## string expected + errColonExpected, ## ``:`` expected + errCommaExpected, ## ``,`` expected + errBracketRiExpected, ## ``]`` expected + errCurlyRiExpected, ## ``}`` expected + errQuoteExpected, ## ``"`` or ``'`` expected + errEOC_Expected, ## ``*/`` expected + errEofExpected, ## EOF expected + errExprExpected ## expr expected + + ParserState = enum + stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma, + stateExpectObjectComma, stateExpectColon, stateExpectValue + + JsonParser* = object of BaseLexer ## the parser object. + a*: string + tok*: TokKind + kind: JsonEventKind + err: JsonError + state: seq[ParserState] + filename: string + rawStringLiterals: bool + + JsonKindError* = object of ValueError ## raised by the ``to`` macro if the + ## JSON kind is incorrect. + JsonParsingError* = object of ValueError ## is raised for a JSON error + +const + errorMessages*: array[JsonError, string] = [ + "no error", + "invalid token", + "string expected", + "':' expected", + "',' expected", + "']' expected", + "'}' expected", + "'\"' or \"'\" expected", + "'*/' expected", + "EOF expected", + "expression expected" + ] + tokToStr: array[TokKind, string] = [ + "invalid token", + "EOF", + "string literal", + "int literal", + "float literal", + "true", + "false", + "null", + "{", "}", "[", "]", ":", "," + ] + +proc open*(my: var JsonParser, input: Stream, filename: string; + rawStringLiterals = false) = + ## initializes the parser with an input stream. `Filename` is only used + ## for nice error messages. If `rawStringLiterals` is true, string literals + ## are kepts with their surrounding quotes and escape sequences in them are + ## left untouched too. + lexbase.open(my, input) + my.filename = filename + my.state = @[stateStart] + my.kind = jsonError + my.a = "" + my.rawStringLiterals = rawStringLiterals + +proc close*(my: var JsonParser) {.inline.} = + ## closes the parser `my` and its associated input stream. + lexbase.close(my) + +proc str*(my: JsonParser): string {.inline.} = + ## returns the character data for the events: ``jsonInt``, ``jsonFloat``, + ## ``jsonString`` + assert(my.kind in {jsonInt, jsonFloat, jsonString}) + return my.a + +proc getInt*(my: JsonParser): BiggestInt {.inline.} = + ## returns the number for the event: ``jsonInt`` + assert(my.kind == jsonInt) + return parseBiggestInt(my.a) + +proc getFloat*(my: JsonParser): float {.inline.} = + ## returns the number for the event: ``jsonFloat`` + assert(my.kind == jsonFloat) + return parseFloat(my.a) + +proc kind*(my: JsonParser): JsonEventKind {.inline.} = + ## returns the current event type for the JSON parser + return my.kind + +proc getColumn*(my: JsonParser): int {.inline.} = + ## get the current column the parser has arrived at. + result = getColNumber(my, my.bufpos) + +proc getLine*(my: JsonParser): int {.inline.} = + ## get the current line the parser has arrived at. + result = my.lineNumber + +proc getFilename*(my: JsonParser): string {.inline.} = + ## get the filename of the file that the parser processes. + result = my.filename + +proc errorMsg*(my: JsonParser): string = + ## returns a helpful error message for the event ``jsonError`` + assert(my.kind == jsonError) + result = "$1($2, $3) Error: $4" % [ + my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]] + +proc errorMsgExpected*(my: JsonParser, e: string): string = + ## returns an error message "`e` expected" in the same format as the + ## other error messages + result = "$1($2, $3) Error: $4" % [ + my.filename, $getLine(my), $getColumn(my), e & " expected"] + +proc handleHexChar(c: char, x: var int): bool = + result = true # Success + case c + of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) + of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) + of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) + else: result = false # error + +proc parseEscapedUTF16*(buf: cstring, pos: var int): int = + result = 0 + #UTF-16 escape is always 4 bytes. + for _ in 0..3: + if handleHexChar(buf[pos], result): + inc(pos) + else: + return -1 + +proc parseString(my: var JsonParser): TokKind = + result = tkString + var pos = my.bufpos + 1 + var buf = my.buf + if my.rawStringLiterals: + add(my.a, '"') + while true: + case buf[pos] + of '\0': + my.err = errQuoteExpected + result = tkError + break + of '"': + if my.rawStringLiterals: + add(my.a, '"') + inc(pos) + break + of '\\': + if my.rawStringLiterals: + add(my.a, '\\') + case buf[pos+1] + of '\\', '"', '\'', '/': + add(my.a, buf[pos+1]) + inc(pos, 2) + of 'b': + add(my.a, '\b') + inc(pos, 2) + of 'f': + add(my.a, '\f') + inc(pos, 2) + of 'n': + add(my.a, '\L') + inc(pos, 2) + of 'r': + add(my.a, '\C') + inc(pos, 2) + of 't': + add(my.a, '\t') + inc(pos, 2) + of 'u': + if my.rawStringLiterals: + add(my.a, 'u') + inc(pos, 2) + var pos2 = pos + var r = parseEscapedUTF16(buf, pos) + if r < 0: + my.err = errInvalidToken + break + # Deal with surrogates + if (r and 0xfc00) == 0xd800: + if buf[pos] != '\\' or buf[pos+1] != 'u': + my.err = errInvalidToken + break + inc(pos, 2) + var s = parseEscapedUTF16(buf, pos) + if (s and 0xfc00) == 0xdc00 and s > 0: + r = 0x10000 + (((r - 0xd800) shl 10) or (s - 0xdc00)) + else: + my.err = errInvalidToken + break + if my.rawStringLiterals: + let length = pos - pos2 + for i in 1 .. length: + if buf[pos2] in {'0'..'9', 'A'..'F', 'a'..'f'}: + add(my.a, buf[pos2]) + inc pos2 + else: + break + else: + add(my.a, toUTF8(Rune(r))) + else: + # don't bother with the error + add(my.a, buf[pos]) + inc(pos) + of '\c': + pos = lexbase.handleCR(my, pos) + buf = my.buf + add(my.a, '\c') + of '\L': + pos = lexbase.handleLF(my, pos) + buf = my.buf + add(my.a, '\L') + else: + add(my.a, buf[pos]) + inc(pos) + my.bufpos = pos # store back + +proc skip(my: var JsonParser) = + var pos = my.bufpos + var buf = my.buf + while true: + case buf[pos] + of '/': + if buf[pos+1] == '/': + # skip line comment: + inc(pos, 2) + while true: + case buf[pos] + of '\0': + break + of '\c': + pos = lexbase.handleCR(my, pos) + buf = my.buf + break + of '\L': + pos = lexbase.handleLF(my, pos) + buf = my.buf + break + else: + inc(pos) + elif buf[pos+1] == '*': + # skip long comment: + inc(pos, 2) + while true: + case buf[pos] + of '\0': + my.err = errEOC_Expected + break + of '\c': + pos = lexbase.handleCR(my, pos) + buf = my.buf + of '\L': + pos = lexbase.handleLF(my, pos) + buf = my.buf + of '*': + inc(pos) + if buf[pos] == '/': + inc(pos) + break + else: + inc(pos) + else: + break + of ' ', '\t': + inc(pos) + of '\c': + pos = lexbase.handleCR(my, pos) + buf = my.buf + of '\L': + pos = lexbase.handleLF(my, pos) + buf = my.buf + else: + break + my.bufpos = pos + +proc parseNumber(my: var JsonParser) = + var pos = my.bufpos + var buf = my.buf + if buf[pos] == '-': + add(my.a, '-') + inc(pos) + if buf[pos] == '.': + add(my.a, "0.") + inc(pos) + else: + while buf[pos] in Digits: + add(my.a, buf[pos]) + inc(pos) + if buf[pos] == '.': + add(my.a, '.') + inc(pos) + # digits after the dot: + while buf[pos] in Digits: + add(my.a, buf[pos]) + inc(pos) + if buf[pos] in {'E', 'e'}: + add(my.a, buf[pos]) + inc(pos) + if buf[pos] in {'+', '-'}: + add(my.a, buf[pos]) + inc(pos) + while buf[pos] in Digits: + add(my.a, buf[pos]) + inc(pos) + my.bufpos = pos + +proc parseName(my: var JsonParser) = + var pos = my.bufpos + var buf = my.buf + if buf[pos] in IdentStartChars: + while buf[pos] in IdentChars: + add(my.a, buf[pos]) + inc(pos) + my.bufpos = pos + +proc getTok*(my: var JsonParser): TokKind = + setLen(my.a, 0) + skip(my) # skip whitespace, comments + case my.buf[my.bufpos] + of '-', '.', '0'..'9': + parseNumber(my) + if {'.', 'e', 'E'} in my.a: + result = tkFloat + else: + result = tkInt + of '"': + result = parseString(my) + of '[': + inc(my.bufpos) + result = tkBracketLe + of '{': + inc(my.bufpos) + result = tkCurlyLe + of ']': + inc(my.bufpos) + result = tkBracketRi + of '}': + inc(my.bufpos) + result = tkCurlyRi + of ',': + inc(my.bufpos) + result = tkComma + of ':': + inc(my.bufpos) + result = tkColon + of '\0': + result = tkEof + of 'a'..'z', 'A'..'Z', '_': + parseName(my) + case my.a + of "null": result = tkNull + of "true": result = tkTrue + of "false": result = tkFalse + else: result = tkError + else: + inc(my.bufpos) + result = tkError + my.tok = result + + +proc next*(my: var JsonParser) = + ## retrieves the first/next event. This controls the parser. + var tk = getTok(my) + var i = my.state.len-1 + # the following code is a state machine. If we had proper coroutines, + # the code could be much simpler. + case my.state[i] + of stateEof: + if tk == tkEof: + my.kind = jsonEof + else: + my.kind = jsonError + my.err = errEofExpected + of stateStart: + # tokens allowed? + case tk + of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: + my.state[i] = stateEof # expect EOF next! + my.kind = JsonEventKind(ord(tk)) + of tkBracketLe: + my.state.add(stateArray) # we expect any + my.kind = jsonArrayStart + of tkCurlyLe: + my.state.add(stateObject) + my.kind = jsonObjectStart + of tkEof: + my.kind = jsonEof + else: + my.kind = jsonError + my.err = errEofExpected + of stateObject: + case tk + of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: + my.state.add(stateExpectColon) + my.kind = JsonEventKind(ord(tk)) + of tkBracketLe: + my.state.add(stateExpectColon) + my.state.add(stateArray) + my.kind = jsonArrayStart + of tkCurlyLe: + my.state.add(stateExpectColon) + my.state.add(stateObject) + my.kind = jsonObjectStart + of tkCurlyRi: + my.kind = jsonObjectEnd + discard my.state.pop() + else: + my.kind = jsonError + my.err = errCurlyRiExpected + of stateArray: + case tk + of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: + my.state.add(stateExpectArrayComma) # expect value next! + my.kind = JsonEventKind(ord(tk)) + of tkBracketLe: + my.state.add(stateExpectArrayComma) + my.state.add(stateArray) + my.kind = jsonArrayStart + of tkCurlyLe: + my.state.add(stateExpectArrayComma) + my.state.add(stateObject) + my.kind = jsonObjectStart + of tkBracketRi: + my.kind = jsonArrayEnd + discard my.state.pop() + else: + my.kind = jsonError + my.err = errBracketRiExpected + of stateExpectArrayComma: + case tk + of tkComma: + discard my.state.pop() + next(my) + of tkBracketRi: + my.kind = jsonArrayEnd + discard my.state.pop() # pop stateExpectArrayComma + discard my.state.pop() # pop stateArray + else: + my.kind = jsonError + my.err = errBracketRiExpected + of stateExpectObjectComma: + case tk + of tkComma: + discard my.state.pop() + next(my) + of tkCurlyRi: + my.kind = jsonObjectEnd + discard my.state.pop() # pop stateExpectObjectComma + discard my.state.pop() # pop stateObject + else: + my.kind = jsonError + my.err = errCurlyRiExpected + of stateExpectColon: + case tk + of tkColon: + my.state[i] = stateExpectValue + next(my) + else: + my.kind = jsonError + my.err = errColonExpected + of stateExpectValue: + case tk + of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: + my.state[i] = stateExpectObjectComma + my.kind = JsonEventKind(ord(tk)) + of tkBracketLe: + my.state[i] = stateExpectObjectComma + my.state.add(stateArray) + my.kind = jsonArrayStart + of tkCurlyLe: + my.state[i] = stateExpectObjectComma + my.state.add(stateObject) + my.kind = jsonObjectStart + else: + my.kind = jsonError + my.err = errExprExpected + +proc raiseParseErr*(p: JsonParser, msg: string) {.noinline, noreturn.} = + ## raises an `EJsonParsingError` exception. + raise newException(JsonParsingError, errorMsgExpected(p, msg)) + +proc eat*(p: var JsonParser, tok: TokKind) = + if p.tok == tok: discard getTok(p) + else: raiseParseErr(p, tokToStr[tok]) From 5b176f14a2d6ef12e91027d736d60dcaa799347c Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Thu, 17 May 2018 12:49:17 +0200 Subject: [PATCH 212/214] Provide configuration for Genode toolchain --- config/nim.cfg | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config/nim.cfg b/config/nim.cfg index 9b3172e90a..e11826587e 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -243,3 +243,11 @@ vcc.cpp.options.size = "/O1" # Configuration for the Tiny C Compiler: tcc.options.always = "-w" + +# Configuration for the Genode toolchain +amd64.genode.gcc.cpp.exe = "genode-x86-g++" +amd64.genode.gcc.exe = "genode-x86-gcc" +amd64.genode.gcc.path = "/usr/local/genode-gcc/bin" +arm.genode.gcc.cpp.exe = "genode-arm-g++" +arm.genode.gcc.exe = "genode-arm-gcc" +arm.genode.gcc.path = "/usr/local/genode-gcc/bin" From 43b1ac07d4bb7eeecec45f8dca50442618f2608b Mon Sep 17 00:00:00 2001 From: coffeepots Date: Fri, 18 May 2018 18:37:28 +0100 Subject: [PATCH 213/214] Fix typo in "out of bounds" error message --- compiler/vm.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index dcb4cefd71..cbd304caad 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -441,7 +441,7 @@ proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) = node.sons[i] = newNodeI(typeKind, info) const - errIndexOutOfBounds = "index ouf of bounds" + errIndexOutOfBounds = "index out of bounds" errNilAccess = "attempt to access a nil address" errOverOrUnderflow = "over- or underflow" errConstantDivisionByZero = "division by zero" From 06bdf8392bd3e597dbe3ef12c7a819b60e32d7ac Mon Sep 17 00:00:00 2001 From: Dmitry Atamanov Date: Fri, 18 May 2018 22:13:29 +0300 Subject: [PATCH 214/214] Fixes CritBitTree.inc's bug (#7838) * Fixes CritBitTree.inc's bug * Update changelog --- changelog.md | 1 + lib/pure/collections/critbits.nim | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index cbefbc421e..f9daf55d13 100644 --- a/changelog.md +++ b/changelog.md @@ -74,6 +74,7 @@ deprecated. - The `terminal` module now exports additional procs for generating ANSI color codes as strings. +- Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc. ### Language additions diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 95fffdf88c..5ae5e26b21 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -163,13 +163,13 @@ proc containsOrIncl*(c: var CritBitTree[void], key: string): bool = var n = rawInsert(c, key) result = c.count == oldCount -proc inc*(c: var CritBitTree[int]; key: string) = - ## counts the 'key'. +proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) = + ## increments `c[key]` by `val`. let oldCount = c.count var n = rawInsert(c, key) - if c.count == oldCount: + if c.count == oldCount or oldCount == 0: # not a new key: - inc n.val + inc n.val, val proc incl*(c: var CritBitTree[void], key: string) = ## includes `key` in `c`. @@ -352,3 +352,13 @@ when isMainModule: assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"] assert toSeq(r.itemsWithPrefix("de")) == @["definition"] + var c = CritBitTree[int]() + + c.inc("a") + assert c["a"] == 1 + + c.inc("a", 4) + assert c["a"] == 5 + + c.inc("a", -5) + assert c["a"] == 0