diff options
Diffstat (limited to 'compiler/msgs.nim')
-rw-r--r-- | compiler/msgs.nim | 239 |
1 files changed, 81 insertions, 158 deletions
diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 151291ffb..197d6ca2a 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -9,83 +9,28 @@ import options, strutils, os, tables, ropes, platform, terminal, macros, - configuration + lineinfos -#type -# MsgConfig* = ref object of RootObj - -type - TFileInfo* = object - fullPath: string # This is a canonical full filesystem path - projPath*: string # This is relative to the project's root - shortName*: string # short name of the module - quotedName*: Rope # cached quoted short name for codegen - # purposes - quotedFullName*: Rope # cached quoted full name for codegen - # purposes - - lines*: seq[Rope] # the source code of the module - # used for better error messages and - # embedding the original source in the - # generated code - dirtyfile: string # the file that is actually read into memory - # and parsed; usually 'nil' but is used - # for 'nimsuggest' - hash*: string # the checksum of the file - when defined(nimpretty): - fullContent*: string - FileIndex* = distinct int32 - TLineInfo* = object # This is designed to be as small as possible, - # because it is used - # in syntax nodes. We save space here by using - # two int16 and an int32. - # On 64 bit and on 32 bit systems this is - # only 8 bytes. - line*: uint16 - col*: int16 - fileIndex*: FileIndex - when defined(nimpretty): - offsetA*, offsetB*: int - commentOffsetA*, commentOffsetB*: int - - TErrorOutput* = enum - eStdOut - eStdErr - - TErrorOutputs* = set[TErrorOutput] - - ERecoverableError* = object of ValueError - ESuggestDone* = object of Exception - -proc `==`*(a, b: FileIndex): bool {.borrow.} - - -const - InvalidFileIDX* = FileIndex(-1) - -var - filenameToIndexTbl = initTable[string, FileIndex]() - fileInfos*: seq[TFileInfo] = @[] - systemFileIdx*: FileIndex - -proc toCChar*(c: char): string = +proc toCChar*(c: char; result: var string) = case c - of '\0'..'\x1F', '\x7F'..'\xFF': result = '\\' & toOctal(c) - of '\'', '\"', '\\', '?': result = '\\' & c - else: result = $(c) + of '\0'..'\x1F', '\x7F'..'\xFF': + result.add '\\' + result.add toOctal(c) + of '\'', '\"', '\\', '?': + result.add '\\' + result.add c + else: + result.add c proc makeCString*(s: string): Rope = - const - MaxLineLength = 64 + const MaxLineLength = 64 result = nil var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1) add(res, "\"") for i in countup(0, len(s) - 1): if (i + 1) mod MaxLineLength == 0: - add(res, '\"') - add(res, '\L') - add(res, '\"') - add(res, toCChar(s[i])) + add(res, "\"\L\"") + toCChar(s[i], res) add(res, '\"') add(result, rope(res)) @@ -110,8 +55,8 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo = result.fullContent = "" when defined(nimpretty): - proc fileSection*(fid: FileIndex; a, b: int): string = - substr(fileInfos[fid.int].fullContent, a, b) + proc fileSection*(conf: ConfigRef; fid: FileIndex; a, b: int): string = + substr(conf.m.fileInfos[fid.int].fullContent, a, b) proc fileInfoKnown*(conf: ConfigRef; filename: string): bool = var @@ -120,7 +65,7 @@ proc fileInfoKnown*(conf: ConfigRef; filename: string): bool = canon = canonicalizePath(conf, filename) except: canon = filename - result = filenameToIndexTbl.hasKey(canon) + result = conf.m.filenameToIndexTbl.hasKey(canon) proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex = var @@ -136,14 +81,14 @@ proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): Fil # This flag indicates that we are working with such a path here pseudoPath = true - if filenameToIndexTbl.hasKey(canon): - result = filenameToIndexTbl[canon] + if conf.m.filenameToIndexTbl.hasKey(canon): + result = conf.m.filenameToIndexTbl[canon] else: isKnownFile = false - result = fileInfos.len.FileIndex - fileInfos.add(newFileInfo(canon, if pseudoPath: filename - else: shortenDir(conf, canon))) - filenameToIndexTbl[canon] = result + result = conf.m.fileInfos.len.FileIndex + conf.m.fileInfos.add(newFileInfo(canon, if pseudoPath: filename + else: shortenDir(conf, canon))) + conf.m.filenameToIndexTbl[canon] = result proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex = var dummy: bool @@ -162,36 +107,19 @@ proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} = proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope -proc unknownLineInfo*(): TLineInfo = - result.line = uint16(0) - result.col = int16(-1) - result.fileIndex = InvalidFileIDX - -type - Severity* {.pure.} = enum ## VS Code only supports these three - Hint, Warning, Error - -var - msgContext: seq[TLineInfo] = @[] - lastError = unknownLineInfo() - - errorOutputs* = {eStdOut, eStdErr} - writelnHook*: proc (output: string) {.closure.} - structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string; severity: Severity) {.closure.} - proc concat(strings: openarray[string]): string = var totalLen = 0 for s in strings: totalLen += s.len result = newStringOfCap totalLen for s in strings: result.add s -proc suggestWriteln*(s: string) = - if eStdOut in errorOutputs: - if isNil(writelnHook): +proc suggestWriteln*(conf: ConfigRef; s: string) = + if eStdOut in conf.m.errorOutputs: + if isNil(conf.writelnHook): writeLine(stdout, s) flushFile(stdout) else: - writelnHook(s) + conf.writelnHook(s) proc msgQuit*(x: int8) = quit x proc msgQuit*(x: string) = quit x @@ -212,47 +140,47 @@ const HintTitle = "Hint: " HintColor = fgGreen -proc getInfoContextLen*(): int = return msgContext.len -proc setInfoContextLen*(L: int) = setLen(msgContext, L) +proc getInfoContextLen*(conf: ConfigRef): int = return conf.m.msgContext.len +proc setInfoContextLen*(conf: ConfigRef; L: int) = setLen(conf.m.msgContext, L) -proc pushInfoContext*(info: TLineInfo) = - msgContext.add(info) +proc pushInfoContext*(conf: ConfigRef; info: TLineInfo) = + conf.m.msgContext.add(info) -proc popInfoContext*() = - setLen(msgContext, len(msgContext) - 1) +proc popInfoContext*(conf: ConfigRef) = + setLen(conf.m.msgContext, len(conf.m.msgContext) - 1) -proc getInfoContext*(index: int): TLineInfo = - let L = msgContext.len +proc getInfoContext*(conf: ConfigRef; index: int): TLineInfo = + let L = conf.m.msgContext.len let i = if index < 0: L + index else: index if i >=% L: result = unknownLineInfo() - else: result = msgContext[i] + else: result = conf.m.msgContext[i] template toFilename*(conf: ConfigRef; fileIdx: FileIndex): string = - (if fileIdx.int32 < 0: "???" else: fileInfos[fileIdx.int32].projPath) + (if fileIdx.int32 < 0: "???" else: conf.m.fileInfos[fileIdx.int32].projPath) proc toFullPath*(conf: ConfigRef; fileIdx: FileIndex): string = if fileIdx.int32 < 0: result = "???" - else: result = fileInfos[fileIdx.int32].fullPath + else: result = conf.m.fileInfos[fileIdx.int32].fullPath proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: string) = assert fileIdx.int32 >= 0 - fileInfos[fileIdx.int32].dirtyFile = filename + conf.m.fileInfos[fileIdx.int32].dirtyFile = filename proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) = assert fileIdx.int32 >= 0 - shallowCopy(fileInfos[fileIdx.int32].hash, hash) + shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash) proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string = assert fileIdx.int32 >= 0 - shallowCopy(result, fileInfos[fileIdx.int32].hash) + shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash) proc toFullPathConsiderDirty*(conf: ConfigRef; fileIdx: FileIndex): string = if fileIdx.int32 < 0: result = "???" - elif not fileInfos[fileIdx.int32].dirtyFile.isNil: - result = fileInfos[fileIdx.int32].dirtyFile + elif not conf.m.fileInfos[fileIdx.int32].dirtyFile.isNil: + result = conf.m.fileInfos[fileIdx.int32].dirtyFile else: - result = fileInfos[fileIdx.int32].fullPath + result = conf.m.fileInfos[fileIdx.int32].fullPath template toFilename*(conf: ConfigRef; info: TLineInfo): string = toFilename(conf, info.fileIndex) @@ -264,9 +192,9 @@ proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string = if info.fileIndex.int32 < 0: result = "???" elif optListFullPaths in conf.globalOptions: - result = fileInfos[info.fileIndex.int32].fullPath + result = conf.m.fileInfos[info.fileIndex.int32].fullPath else: - result = fileInfos[info.fileIndex.int32].projPath + result = conf.m.fileInfos[info.fileIndex.int32].projPath proc toLinenumber*(info: TLineInfo): int {.inline.} = result = int info.line @@ -288,12 +216,6 @@ proc `??`* (conf: ConfigRef; info: TLineInfo, filename: string): bool = # only for debugging purposes result = filename in toFilename(conf, info) -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 - ## close token. - type MsgFlag* = enum ## flags altering msgWriteln behavior msgStdout, ## force writing to stdout, even stderr is default @@ -310,14 +232,14 @@ proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) = ## support. #if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return - if not isNil(writelnHook) and msgSkipHook notin flags: - writelnHook(s) + if not isNil(conf.writelnHook) and msgSkipHook notin flags: + conf.writelnHook(s) elif optStdout in conf.globalOptions or msgStdout in flags: - if eStdOut in errorOutputs: + if eStdOut in conf.m.errorOutputs: writeLine(stdout, s) flushFile(stdout) else: - if eStdErr in errorOutputs: + if eStdErr in conf.m.errorOutputs: writeLine(stderr, s) # On Windows stderr is fully-buffered when piped, regardless of C std. when defined(windows): @@ -348,17 +270,17 @@ macro callStyledWriteLineStderr(args: varargs[typed]): untyped = result.add(arg) template callWritelnHook(args: varargs[string, `$`]) = - writelnHook concat(args) + conf.writelnHook concat(args) template styledMsgWriteln*(args: varargs[typed]) = - if not isNil(writelnHook): + if not isNil(conf.writelnHook): callIgnoringStyle(callWritelnHook, nil, args) elif optStdout in conf.globalOptions: - if eStdOut in errorOutputs: + if eStdOut in conf.m.errorOutputs: callIgnoringStyle(writeLine, stdout, args) flushFile(stdout) else: - if eStdErr in errorOutputs: + if eStdErr in conf.m.errorOutputs: if optUseColors in conf.globalOptions: callStyledWriteLineStderr(args) else: @@ -389,7 +311,7 @@ proc log*(s: string) {.procvar.} = proc quit(conf: ConfigRef; msg: TMsgKind) = if defined(debug) or msg == errInternal or hintStackTrace in conf.notes: - if stackTraceAvailable() and isNil(writelnHook): + if stackTraceAvailable() and isNil(conf.writelnHook): writeStackTrace() else: styledMsgWriteln(fgRed, "No stack traceback available\n" & @@ -420,19 +342,19 @@ proc exactEquals*(a, b: TLineInfo): bool = 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(conf, msgContext[i], instantiationFrom, - Severity.Error) + for i in 0 ..< len(conf.m.msgContext): + if conf.m.msgContext[i] != lastinfo and conf.m.msgContext[i] != info: + if conf.structuredErrorHook != nil: + conf.structuredErrorHook(conf, conf.m.msgContext[i], instantiationFrom, + Severity.Error) else: styledMsgWriteln(styleBright, - PosFormat % [toMsgFilename(conf, msgContext[i]), - coordToStr(msgContext[i].line.int), - coordToStr(msgContext[i].col+1)], + PosFormat % [toMsgFilename(conf, conf.m.msgContext[i]), + coordToStr(conf.m.msgContext[i].line.int), + coordToStr(conf.m.msgContext[i].col+1)], resetStyle, instantiationFrom) - info = msgContext[i] + info = conf.m.msgContext[i] proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool = msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions @@ -468,8 +390,9 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = inc(conf.hintCounter) let s = msgKindToString(msg) % args - if structuredErrorHook != nil: - structuredErrorHook(conf, unknownLineInfo(), s & (if kind != nil: KindFormat % kind else: ""), sev) + if conf.structuredErrorHook != nil: + conf.structuredErrorHook(conf, unknownLineInfo(), + s & (if kind != nil: KindFormat % kind else: ""), sev) if not ignoreMsgBecauseOfIdeTools(conf, msg): if kind != nil: @@ -518,7 +441,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, # we try to filter error messages so that not two error message # in the same file and line are produced: #ignoreMsg = lastError == info and eh != doAbort - lastError = info + conf.m.lastError = info of warnMin..warnMax: sev = Severity.Warning ignoreMsg = optWarns notin conf.options or msg notin conf.notes @@ -542,8 +465,8 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, let s = getMessageStr(msg, arg) if not ignoreMsg: - if structuredErrorHook != nil: - structuredErrorHook(conf, info, s & (if kind != nil: KindFormat % kind else: ""), sev) + if conf.structuredErrorHook != nil: + conf.structuredErrorHook(conf, info, s & (if kind != nil: KindFormat % kind else: ""), sev) if not ignoreMsgBecauseOfIdeTools(conf, msg): if kind != nil: styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s, @@ -557,7 +480,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, 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} + conf.m.errorOutputs = {eStdOut, eStdErr} liMessage(conf, info, msg, arg, doAbort) proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") = @@ -579,12 +502,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 conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return + if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return writeContext(conf, info) liMessage(conf, info, errInternal, errMsg, doAbort) proc internalError*(conf: ConfigRef; errMsg: string) = - if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return + if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return writeContext(conf, unknownLineInfo()) rawMessage(conf, errInternal, errMsg) @@ -596,36 +519,36 @@ template internalAssert*(conf: ConfigRef, e: bool) = if not e: internalError(conf, $instantiationInfo()) proc addSourceLine*(conf: ConfigRef; fileIdx: FileIndex, line: string) = - fileInfos[fileIdx.int32].lines.add line.rope + conf.m.fileInfos[fileIdx.int32].lines.add line.rope proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope = if i.fileIndex.int32 < 0: return nil - if not optPreserveOrigSource(conf) and fileInfos[i.fileIndex.int32].lines.len == 0: + if not optPreserveOrigSource(conf) and conf.m.fileInfos[i.fileIndex.int32].lines.len == 0: try: for line in lines(toFullPath(conf, i)): addSourceLine conf, i.fileIndex, line.string except IOError: discard - assert i.fileIndex.int32 < fileInfos.len + assert i.fileIndex.int32 < conf.m.fileInfos.len # can happen if the error points to EOF: - if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil + if i.line.int > conf.m.fileInfos[i.fileIndex.int32].lines.len: return nil - result = fileInfos[i.fileIndex.int32].lines[i.line.int-1] + result = conf.m.fileInfos[i.fileIndex.int32].lines[i.line.int-1] proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope = assert i.fileIndex.int32 >= 0 if optExcessiveStackTrace in conf.globalOptions: - result = fileInfos[i.fileIndex.int32].quotedFullName + result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName else: - result = fileInfos[i.fileIndex.int32].quotedName + result = conf.m.fileInfos[i.fileIndex.int32].quotedName proc listWarnings*(conf: ConfigRef) = msgWriteln(conf, "Warnings:") for warn in warnMin..warnMax: msgWriteln(conf, " [$1] $2" % [ if warn in conf.notes: "x" else: " ", - configuration.WarningsToStr[ord(warn) - ord(warnMin)] + lineinfos.WarningsToStr[ord(warn) - ord(warnMin)] ]) proc listHints*(conf: ConfigRef) = @@ -633,5 +556,5 @@ proc listHints*(conf: ConfigRef) = for hint in hintMin..hintMax: msgWriteln(conf, " [$1] $2" % [ if hint in conf.notes: "x" else: " ", - configuration.HintsToStr[ord(hint) - ord(hintMin)] + lineinfos.HintsToStr[ord(hint) - ord(hintMin)] ]) |