# # # 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 `TMsgKind` enum as well as the ## `TLineInfo` object. import ropes, pathutils import std/[hashes, tables] const explanationsBaseUrl* = "https://nim-lang.github.io/Nim" # was: "https://nim-lang.org/docs" but we're now usually showing devel docs # instead of latest release docs. proc createDocLink*(urlSuffix: string): string = # os.`/` is not appropriate for urls. result = explanationsBaseUrl if urlSuffix.len > 0 and urlSuffix[0] == '/': result.add urlSuffix else: result.add "/" & urlSuffix type TMsgKind* = enum # fatal errors errUnknown, errFatal, errInternal, # non-fatal errors errIllFormedAstX, errCannotOpenFile, errXExpected, errRstMissingClosing, errRstGridTableNotImplemented, errRstMarkdownIllformedTable, errRstIllformedTable, errRstNewSectionExpected, errRstGeneralParseError, errRstInvalidDirectiveX, errRstInvalidField, errRstFootnoteMismatch, errRstSandboxedDirective, errProveInit, # deadcode errGenerated, errFailedMove, errUser, # warnings warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape", warnXIsNeverRead = "XIsNeverRead", warnXmightNotBeenInit = "XmightNotBeenInit", warnDeprecated = "Deprecated", warnConfigDeprecated = "ConfigDeprecated", warnDotLikeOps = "DotLikeOps", warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic", warnRstRedefinitionOfLabel = "RedefinitionOfLabel", warnRstUnknownSubstitutionX = "UnknownSubstitutionX", warnRstAmbiguousLink = "AmbiguousLink", warnRstBrokenLink = "BrokenLink", warnRstLanguageXNotSupported = "LanguageXNotSupported", warnRstFieldXNotSupported = "FieldXNotSupported", warnRstUnusedImportdoc = "UnusedImportdoc", warnRstStyle = "warnRstStyle", warnCommentXIgnored = "CommentXIgnored", warnTypelessParam = "TypelessParam", warnUseBase = "UseBase", warnWriteToForeignHeap = "WriteToForeignHeap", warnUnsafeCode = "UnsafeCode", warnUnusedImportX = "UnusedImport", warnInheritFromException = "InheritFromException", warnEachIdentIsTuple = "EachIdentIsTuple", warnUnsafeSetLen = "UnsafeSetLen", warnUnsafeDefault = "UnsafeDefault", warnProveInit = "ProveInit", warnProveField = "ProveField", warnProveIndex = "ProveIndex", warnUnreachableElse = "UnreachableElse", warnUnreachableCode = "UnreachableCode", warnStaticIndexCheck = "IndexCheck", warnGcUnsafe = "GcUnsafe", warnGcUnsafe2 = "GcUnsafe2", warnUninit = "Uninit", warnGcMem = "GcMem", warnDestructor = "Destructor", warnLockLevel = "LockLevel", # deadcode warnResultShadowed = "ResultShadowed", warnInconsistentSpacing = "Spacing", warnCaseTransition = "CaseTransition", warnCycleCreated = "CycleCreated", warnObservableStores = "ObservableStores", warnStrictNotNil = "StrictNotNil", warnResultUsed = "ResultUsed", warnCannotOpen = "CannotOpen", warnFileChanged = "FileChanged", warnSuspiciousEnumConv = "EnumConv", warnAnyEnumConv = "AnyEnumConv", warnHoleEnumConv = "HoleEnumConv", warnCstringConv = "CStringConv", warnPtrToCstringConv = "PtrToCstringConv", warnEffect = "Effect", warnCastSizes = "CastSizes", # deadcode warnAboveMaxSizeSet = "AboveMaxSizeSet", warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition", warnUnnamedBreak = "UnnamedBreak", warnStmtListLambda = "StmtListLambda", warnBareExcept = "BareExcept", warnImplicitDefaultValue = "ImplicitDefaultValue", warnIgnoredSymbolInjection = "IgnoredSymbolInjection", warnStdPrefix = "StdPrefix" warnUser = "User", warnGlobalVarConstructorTemporary = "GlobalVarConstructorTemporary", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintDuplicateModuleImport = "DuplicateModuleImport", hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded", hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX", hintQuitCalled = "QuitCalled", hintProcessing = "Processing", hintProcessingStmt = "ProcessingStmt", hintCodeBegin = "CodeBegin", hintCodeEnd = "CodeEnd", hintConf = "Conf", hintPath = "Path", hintConditionAlwaysTrue = "CondTrue", hintConditionAlwaysFalse = "CondFalse", hintName = "Name", hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency", hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace", hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro", hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext", hintMsgOrigin = "MsgOrigin", # since 1.3.5 hintDeclaredLoc = "DeclaredLoc", # since 1.5.1 hintUnknownHint = "UnknownHint" const MsgKindToStr*: array[TMsgKind, string] = [ errUnknown: "unknown error", errFatal: "fatal error: $1", errInternal: "internal error: $1", errIllFormedAstX: "illformed AST: $1", errCannotOpenFile: "cannot open '$1'", errXExpected: "'$1' expected", errRstMissingClosing: "$1", errRstGridTableNotImplemented: "grid table is not implemented", errRstMarkdownIllformedTable: "illformed delimiter row of a markdown table", errRstIllformedTable: "Illformed table: $1", errRstNewSectionExpected: "new section expected $1", errRstGeneralParseError: "general parse error", errRstInvalidDirectiveX: "invalid directive: '$1'", errRstInvalidField: "invalid field: $1", errRstFootnoteMismatch: "number of footnotes and their references don't match: $1", errRstSandboxedDirective: "disabled directive: '$1'", errProveInit: "Cannot prove that '$1' is initialized.", # deadcode errGenerated: "$1", errFailedMove: "$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", warnConfigDeprecated: "config file '$1' is deprecated", warnDotLikeOps: "$1", warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)", warnUnknownMagic: "unknown magic '$1' might crash the compiler", warnRstRedefinitionOfLabel: "redefinition of label '$1'", warnRstUnknownSubstitutionX: "unknown substitution '$1'", warnRstAmbiguousLink: "ambiguous doc link $1", warnRstBrokenLink: "broken link '$1'", warnRstLanguageXNotSupported: "language '$1' not supported", warnRstFieldXNotSupported: "field '$1' not supported", warnRstUnusedImportdoc: "importdoc for '$1' is not used", warnRstStyle: "RST style: $1", warnCommentXIgnored: "comment '$1' ignored", warnTypelessParam: "", # deadcode warnUseBase: "use {.base.} for base methods; baseless methods are deprecated", warnWriteToForeignHeap: "write to foreign heap", warnUnsafeCode: "unsafe code: '$1'", warnUnusedImportX: "imported and not used: '$1'", warnInheritFromException: "inherit from a more precise exception type like ValueError, " & "IOError or OSError. If these don't suit, inherit from CatchableError or Defect.", warnEachIdentIsTuple: "each identifier is a tuple", warnUnsafeSetLen: "setLen can potentially expand the sequence, " & "but the element type '$1' doesn't have a valid default value", warnUnsafeDefault: "The '$1' type doesn't have a valid default value", 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", warnUnreachableElse: "unreachable else, all cases are already covered", warnUnreachableCode: "unreachable code after 'return' statement or '{.noReturn.}' proc", warnStaticIndexCheck: "$1", warnGcUnsafe: "not GC-safe: '$1'", warnGcUnsafe2: "$1", warnUninit: "use explicit initialization of '$1' for clarity", 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", # deadcode warnResultShadowed: "Special variable 'result' is shadowed.", warnInconsistentSpacing: "Number of spaces around '$#' is not consistent", warnCaseTransition: "Potential object case transition, instantiate new object instead", warnCycleCreated: "$1", warnObservableStores: "observable stores to '$1'", warnStrictNotNil: "$1", warnResultUsed: "used 'result' variable", warnCannotOpen: "cannot open: $1", warnFileChanged: "file changed: $1", warnSuspiciousEnumConv: "$1", warnAnyEnumConv: "$1", warnHoleEnumConv: "$1", warnCstringConv: "$1", warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; Use a `cast` operation like `cast[cstring](x)`; this will become a compile time error in the future", warnEffect: "$1", warnCastSizes: "$1", # deadcode warnAboveMaxSizeSet: "$1", warnImplicitTemplateRedefinition: "template '$1' is implicitly redefined; this is deprecated, add an explicit .redefine pragma", warnUnnamedBreak: "Using an unnamed break in a block is deprecated; Use a named block with a named break instead", warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead", warnBareExcept: "$1", warnImplicitDefaultValue: "$1", warnIgnoredSymbolInjection: "$1", warnStdPrefix: "$1 needs the 'std' prefix", warnUser: "$1", warnGlobalVarConstructorTemporary: "global variable '$1' initialization requires a temporary variable", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output", hintCC: "CC: $1", hintXDeclaredButNotUsed: "'$1' is declared but not used", hintDuplicateModuleImport: "$1", hintXCannotRaiseY: "$1", 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", hintProcessingStmt: "$1", hintCodeBegin: "generated code listing:", hintCodeEnd: "end of listing", hintConf: "used config file '$1'", hintPath: "added path: '$1'", hintConditionAlwaysTrue: "condition is always true: '$1'", hintConditionAlwaysFalse: "condition is always false: '$1'", hintName: "$1", hintPattern: "$1", hintExecuting: "$1", hintLinking: "$1", hintDependency: "$1", hintSource: "$1", hintPerformance: "$1", hintStackTrace: "$1", hintGCStats: "$1", hintGlobalVar: "global variable declared here", hintExpandMacro: "expanded macro: $1", hintUser: "$1", hintUserRaw: "$1", hintExtendedContext: "$1", hintMsgOrigin: "$1", hintDeclaredLoc: "$1", hintUnknownHint: "unknown hint: $1" ] const fatalMsgs* = {errUnknown..errInternal} errMin* = errUnknown errMax* = errUser warnMin* = warnCannotOpenFile warnMax* = pred(hintSuccess) hintMin* = hintSuccess hintMax* = high(TMsgKind) rstWarnings* = {warnRstRedefinitionOfLabel..warnRstStyle} type TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints TNoteKinds* = set[TNoteKind] proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result = default(array[0..3, TNoteKinds]) result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept, warnStdPrefix} result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin, hintPerformance} result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf, hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC} const NotesVerbosity* = computeNotesVerbosity() errXMustBeCompileTime* = "'$1' can only be used in compile-time context" errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected" type TFileInfo* = object fullPath*: AbsoluteFile # This is a canonical full filesystem path projPath*: RelativeFile # 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[string] # the source code of the module # used for better error messages and # embedding the original source in the # generated code dirtyFile*: AbsoluteFile # the file that is actually read into memory # and parsed; usually "" but is used # for 'nimsuggest' hash*: string # the checksum of the file dirty*: bool # for 'nimpretty' like tooling 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 ValueError proc `==`*(a, b: FileIndex): bool {.borrow.} proc hash*(i: TLineInfo): Hash = hash (i.line.int, i.col.int, i.fileIndex.int) proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} = raise newException(ERecoverableError, msg) const InvalidFileIdx* = FileIndex(-1) unknownLineInfo* = TLineInfo(line: 0, col: -1, fileIndex: InvalidFileIdx) type Severity* {.pure.} = enum ## VS Code only supports these three Hint, Warning, Error const trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions # are produced within comments and string literals commandLineIdx* = FileIndex(-3) type MsgConfig* = object ## does not need to be stored in the incremental cache trackPos*: TLineInfo trackPosAttached*: bool ## whether the tracking position was attached to ## some close token. errorOutputs*: TErrorOutputs msgContext*: seq[tuple[info: TLineInfo, detail: string]] lastError*: TLineInfo filenameToIndexTbl*: Table[string, FileIndex] fileInfos*: seq[TFileInfo] systemFileIdx*: FileIndex proc initMsgConfig*(): MsgConfig = result = MsgConfig(msgContext: @[], lastError: unknownLineInfo, filenameToIndexTbl: initTable[string, FileIndex](), fileInfos: @[], errorOutputs: {eStdOut, eStdErr} ) result.filenameToIndexTbl["???"] = FileIndex(-1)