mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-12 06:18:51 +00:00
big refactoring: parser compiles again
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
389
compiler/configuration.nim
Normal file
389
compiler/configuration.nim
Normal file
@@ -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",
|
||||
]#
|
||||
@@ -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"))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 & " <file>")
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user