big refactoring: parser compiles again
This commit is contained in:
parent
79ec95a9b5
commit
61e57cfa13
15 changed files with 1156 additions and 1228 deletions
|
|
@ -1564,15 +1564,17 @@ proc getInt*(a: PNode): BiggestInt =
|
||||||
case a.kind
|
case a.kind
|
||||||
of nkCharLit..nkUInt64Lit: result = a.intVal
|
of nkCharLit..nkUInt64Lit: result = a.intVal
|
||||||
else:
|
else:
|
||||||
internalError(a.info, "getInt")
|
#internalError(a.info, "getInt")
|
||||||
result = 0
|
doAssert false, "getInt"
|
||||||
|
#result = 0
|
||||||
|
|
||||||
proc getFloat*(a: PNode): BiggestFloat =
|
proc getFloat*(a: PNode): BiggestFloat =
|
||||||
case a.kind
|
case a.kind
|
||||||
of nkFloatLiterals: result = a.floatVal
|
of nkFloatLiterals: result = a.floatVal
|
||||||
else:
|
else:
|
||||||
internalError(a.info, "getFloat")
|
doAssert false, "getFloat"
|
||||||
result = 0.0
|
#internalError(a.info, "getFloat")
|
||||||
|
#result = 0.0
|
||||||
|
|
||||||
proc getStr*(a: PNode): string =
|
proc getStr*(a: PNode): string =
|
||||||
case a.kind
|
case a.kind
|
||||||
|
|
@ -1581,16 +1583,18 @@ proc getStr*(a: PNode): string =
|
||||||
# let's hope this fixes more problems than it creates:
|
# let's hope this fixes more problems than it creates:
|
||||||
result = nil
|
result = nil
|
||||||
else:
|
else:
|
||||||
internalError(a.info, "getStr")
|
doAssert false, "getStr"
|
||||||
result = ""
|
#internalError(a.info, "getStr")
|
||||||
|
#result = ""
|
||||||
|
|
||||||
proc getStrOrChar*(a: PNode): string =
|
proc getStrOrChar*(a: PNode): string =
|
||||||
case a.kind
|
case a.kind
|
||||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||||
of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
|
of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
|
||||||
else:
|
else:
|
||||||
internalError(a.info, "getStrOrChar")
|
doAssert false, "getStrOrChar"
|
||||||
result = ""
|
#internalError(a.info, "getStrOrChar")
|
||||||
|
#result = ""
|
||||||
|
|
||||||
proc isGenericRoutine*(s: PSym): bool =
|
proc isGenericRoutine*(s: PSym): bool =
|
||||||
case s.kind
|
case s.kind
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
|
||||||
result = lookupInRecord(n.sons[i], field)
|
result = lookupInRecord(n.sons[i], field)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
of nkRecCase:
|
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)
|
result = lookupInRecord(n.sons[0], field)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
|
|
@ -188,10 +188,10 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
|
||||||
of nkOfBranch, nkElse:
|
of nkOfBranch, nkElse:
|
||||||
result = lookupInRecord(lastSon(n.sons[i]), field)
|
result = lookupInRecord(lastSon(n.sons[i]), field)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
else: internalError(n.info, "lookupInRecord(record case branch)")
|
else: return nil
|
||||||
of nkSym:
|
of nkSym:
|
||||||
if n.sym.name.id == field.id: result = n.sym
|
if n.sym.name.id == field.id: result = n.sym
|
||||||
else: internalError(n.info, "lookupInRecord()")
|
else: return nil
|
||||||
|
|
||||||
proc getModule(s: PSym): PSym =
|
proc getModule(s: PSym): PSym =
|
||||||
result = s
|
result = s
|
||||||
|
|
@ -203,7 +203,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
|
||||||
if list.sons[i].kind == nkSym:
|
if list.sons[i].kind == nkSym:
|
||||||
result = list.sons[i].sym
|
result = list.sons[i].sym
|
||||||
if result.name.id == ident.id: return
|
if result.name.id == ident.id: return
|
||||||
else: internalError(list.info, "getSymFromList")
|
else: return nil
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc hashNode(p: RootRef): Hash =
|
proc hashNode(p: RootRef): Hash =
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ template bootSwitch(name, expr, userString) =
|
||||||
|
|
||||||
bootSwitch(usedRelease, defined(release), "-d:release")
|
bootSwitch(usedRelease, defined(release), "-d:release")
|
||||||
bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise")
|
bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise")
|
||||||
bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas")
|
|
||||||
bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
|
bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
|
||||||
bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
|
bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
|
||||||
bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
|
bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
|
||||||
|
|
@ -27,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
||||||
|
|
||||||
import
|
import
|
||||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform,
|
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.
|
# but some have deps to imported modules. Yay.
|
||||||
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
|
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
|
||||||
|
|
@ -36,24 +35,15 @@ bootSwitch(usedNativeStacktrace,
|
||||||
"-d:nativeStackTrace")
|
"-d:nativeStackTrace")
|
||||||
bootSwitch(usedFFI, hasFFI, "-d:useFFI")
|
bootSwitch(usedFFI, hasFFI, "-d:useFFI")
|
||||||
|
|
||||||
|
|
||||||
proc writeCommandLineUsage*()
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TCmdLinePass* = enum
|
TCmdLinePass* = enum
|
||||||
passCmd1, # first pass over the command line
|
passCmd1, # first pass over the command line
|
||||||
passCmd2, # second pass over the command line
|
passCmd2, # second pass over the command line
|
||||||
passPP # preprocessor called processCommand()
|
passPP # preprocessor called processCommand()
|
||||||
|
|
||||||
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef)
|
|
||||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
|
||||||
config: ConfigRef)
|
|
||||||
|
|
||||||
# implementation
|
|
||||||
|
|
||||||
const
|
const
|
||||||
HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
|
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"
|
"Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -68,7 +58,7 @@ const
|
||||||
|
|
||||||
proc getCommandLineDesc(): string =
|
proc getCommandLineDesc(): string =
|
||||||
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
|
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name, CompileDate, CompileTime]) &
|
CPU[platform.hostCPU].name, CompileDate]) &
|
||||||
Usage
|
Usage
|
||||||
|
|
||||||
proc helpOnError(pass: TCmdLinePass) =
|
proc helpOnError(pass: TCmdLinePass) =
|
||||||
|
|
@ -80,7 +70,7 @@ proc writeAdvancedUsage(pass: TCmdLinePass) =
|
||||||
if pass == passCmd1:
|
if pass == passCmd1:
|
||||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||||
platform.OS[platform.hostOS].name,
|
platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name, CompileDate, CompileTime]) &
|
CPU[platform.hostCPU].name, CompileDate]) &
|
||||||
AdvancedUsage,
|
AdvancedUsage,
|
||||||
{msgStdout})
|
{msgStdout})
|
||||||
msgQuit(0)
|
msgQuit(0)
|
||||||
|
|
@ -89,7 +79,7 @@ proc writeFullhelp(pass: TCmdLinePass) =
|
||||||
if pass == passCmd1:
|
if pass == passCmd1:
|
||||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||||
platform.OS[platform.hostOS].name,
|
platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name, CompileDate, CompileTime]) &
|
CPU[platform.hostCPU].name, CompileDate]) &
|
||||||
Usage & AdvancedUsage,
|
Usage & AdvancedUsage,
|
||||||
{msgStdout})
|
{msgStdout})
|
||||||
msgQuit(0)
|
msgQuit(0)
|
||||||
|
|
@ -98,7 +88,7 @@ proc writeVersionInfo(pass: TCmdLinePass) =
|
||||||
if pass == passCmd1:
|
if pass == passCmd1:
|
||||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||||
platform.OS[platform.hostOS].name,
|
platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name, CompileDate, CompileTime]),
|
CPU[platform.hostCPU].name, CompileDate]),
|
||||||
{msgStdout})
|
{msgStdout})
|
||||||
|
|
||||||
const gitHash = gorge("git log -n 1 --format=%H").strip
|
const gitHash = gorge("git log -n 1 --format=%H").strip
|
||||||
|
|
@ -106,15 +96,12 @@ proc writeVersionInfo(pass: TCmdLinePass) =
|
||||||
msgWriteln("git hash: " & gitHash, {msgStdout})
|
msgWriteln("git hash: " & gitHash, {msgStdout})
|
||||||
|
|
||||||
msgWriteln("active boot switches:" & usedRelease &
|
msgWriteln("active boot switches:" & usedRelease &
|
||||||
usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
|
usedTinyC & usedGnuReadline & usedNativeStacktrace &
|
||||||
usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC,
|
usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC,
|
||||||
{msgStdout})
|
{msgStdout})
|
||||||
msgQuit(0)
|
msgQuit(0)
|
||||||
|
|
||||||
var
|
proc writeCommandLineUsage*(helpWritten: var bool) =
|
||||||
helpWritten: bool
|
|
||||||
|
|
||||||
proc writeCommandLineUsage() =
|
|
||||||
if not helpWritten:
|
if not helpWritten:
|
||||||
msgWriteln(getCommandLineDesc(), {msgStdout})
|
msgWriteln(getCommandLineDesc(), {msgStdout})
|
||||||
helpWritten = true
|
helpWritten = true
|
||||||
|
|
@ -123,11 +110,16 @@ proc addPrefix(switch: string): string =
|
||||||
if len(switch) == 1: result = "-" & switch
|
if len(switch) == 1: result = "-" & switch
|
||||||
else: result = "--" & switch
|
else: result = "--" & switch
|
||||||
|
|
||||||
proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
|
const
|
||||||
if switch == " ": localError(info, errInvalidCmdLineOption, "-")
|
errInvalidCmdLineOption = "invalid command line option: '$1'"
|
||||||
else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
|
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) =
|
info: TLineInfo) =
|
||||||
cmd = ""
|
cmd = ""
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -140,46 +132,41 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
|
||||||
inc(i)
|
inc(i)
|
||||||
if i >= len(switch): arg = ""
|
if i >= len(switch): arg = ""
|
||||||
elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
|
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) =
|
info: TLineInfo) =
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "on": gOptions = gOptions + op
|
of "on": gOptions = gOptions + op
|
||||||
of "off": 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 =
|
info: TLineInfo): bool =
|
||||||
result = false
|
result = false
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "on": gOptions = gOptions + op
|
of "on": gOptions = gOptions + op
|
||||||
of "off": gOptions = gOptions - op
|
of "off": gOptions = gOptions - op
|
||||||
else:
|
of "list": result = true
|
||||||
if arg == "list":
|
else: localError(conf, info, errOnOffOrListExpectedButXFound % arg)
|
||||||
result = true
|
|
||||||
else:
|
|
||||||
localError(info, errOnOffOrListExpectedButXFound, arg)
|
|
||||||
|
|
||||||
proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
|
proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass,
|
||||||
info: TLineInfo) =
|
info: TLineInfo) =
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "on": gGlobalOptions = gGlobalOptions + op
|
of "on": gGlobalOptions = gGlobalOptions + op
|
||||||
of "off": 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) =
|
proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
|
if arg == "":
|
||||||
|
localError(conf, info, "argument for command line option expected: '$1'" % addPrefix(switch))
|
||||||
|
|
||||||
proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
|
if arg != "":
|
||||||
|
localError(conf, info, "invalid argument for command line option: '$1'" % addPrefix(switch))
|
||||||
var
|
|
||||||
enableNotes: TNoteKinds
|
|
||||||
disableNotes: TNoteKinds
|
|
||||||
|
|
||||||
proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
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 id = "" # arg = "X]:on|off"
|
||||||
var i = 0
|
var i = 0
|
||||||
var n = hintMin
|
var n = hintMin
|
||||||
|
|
@ -187,35 +174,40 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||||
add(id, arg[i])
|
add(id, arg[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
if i < len(arg) and (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)
|
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
|
||||||
else: invalidCmdLineOption(pass, orig, info)
|
else: invalidCmdLineOption(conf, pass, orig, info)
|
||||||
if state == wHint:
|
if state == wHint:
|
||||||
let x = findStr(msgs.HintsToStr, id)
|
let x = findStr(configuration.HintsToStr, id)
|
||||||
if x >= 0: n = TNoteKind(x + ord(hintMin))
|
if x >= 0: n = TNoteKind(x + ord(hintMin))
|
||||||
else: localError(info, "unknown hint: " & id)
|
else: localError(conf, info, "unknown hint: " & id)
|
||||||
else:
|
else:
|
||||||
let x = findStr(msgs.WarningsToStr, id)
|
let x = findStr(configuration.WarningsToStr, id)
|
||||||
if x >= 0: n = TNoteKind(x + ord(warnMin))
|
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
|
case substr(arg, i).normalize
|
||||||
of "on":
|
of "on":
|
||||||
incl(gNotes, n)
|
incl(conf.notes, n)
|
||||||
incl(gMainPackageNotes, n)
|
incl(conf.mainPackageNotes, n)
|
||||||
incl(enableNotes, n)
|
incl(conf.enableNotes, n)
|
||||||
of "off":
|
of "off":
|
||||||
excl(gNotes, n)
|
excl(conf.notes, n)
|
||||||
excl(gMainPackageNotes, n)
|
excl(conf.mainPackageNotes, n)
|
||||||
incl(disableNotes, n)
|
incl(conf.disableNotes, n)
|
||||||
excl(ForeignPackageNotes, n)
|
excl(conf.foreignPackageNotes, n)
|
||||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
else: localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
||||||
|
|
||||||
proc processCompile(filename: string) =
|
proc processCompile(conf: ConfigRef; filename: string) =
|
||||||
var found = findFile(filename)
|
var found = findFile(conf, filename)
|
||||||
if found == "": found = 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
|
case switch.normalize
|
||||||
of "gc":
|
of "gc":
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
|
|
@ -227,13 +219,13 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
|
||||||
of "go": result = gSelectedGC == gcGo
|
of "go": result = gSelectedGC == gcGo
|
||||||
of "none": result = gSelectedGC == gcNone
|
of "none": result = gSelectedGC == gcNone
|
||||||
of "stack", "regions": result = gSelectedGC == gcRegions
|
of "stack", "regions": result = gSelectedGC == gcRegions
|
||||||
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||||
of "opt":
|
of "opt":
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "speed": result = contains(gOptions, optOptimizeSpeed)
|
of "speed": result = contains(gOptions, optOptimizeSpeed)
|
||||||
of "size": result = contains(gOptions, optOptimizeSize)
|
of "size": result = contains(gOptions, optOptimizeSize)
|
||||||
of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
|
of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
|
||||||
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
|
||||||
of "verbosity": result = $gVerbosity == arg
|
of "verbosity": result = $gVerbosity == arg
|
||||||
of "app":
|
of "app":
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
|
|
@ -243,12 +235,12 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
|
||||||
not contains(gGlobalOptions, optGenGuiApp)
|
not contains(gGlobalOptions, optGenGuiApp)
|
||||||
of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and
|
of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and
|
||||||
not contains(gGlobalOptions, optGenGuiApp)
|
not contains(gGlobalOptions, optGenGuiApp)
|
||||||
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
|
else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
|
||||||
of "dynliboverride":
|
of "dynliboverride":
|
||||||
result = isDynlibOverride(arg)
|
result = isDynlibOverride(conf, arg)
|
||||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
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
|
case switch.normalize
|
||||||
of "debuginfo": result = contains(gGlobalOptions, optCDebug)
|
of "debuginfo": result = contains(gGlobalOptions, optCDebug)
|
||||||
of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
|
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 "implicitstatic": result = contains(gOptions, optImplicitStatic)
|
||||||
of "patterns": result = contains(gOptions, optPatterns)
|
of "patterns": result = contains(gOptions, optPatterns)
|
||||||
of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace)
|
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 =
|
notRelativeToProj = false): string =
|
||||||
let p = if os.isAbsolute(path) or '$' in path:
|
let p = if os.isAbsolute(path) or '$' in path:
|
||||||
path
|
path
|
||||||
|
|
@ -297,12 +289,12 @@ proc processPath(path: string, info: TLineInfo,
|
||||||
else:
|
else:
|
||||||
options.gProjectPath / path
|
options.gProjectPath / path
|
||||||
try:
|
try:
|
||||||
result = pathSubs(p, info.toFullPath().splitFile().dir)
|
result = pathSubs(conf, p, info.toFullPath().splitFile().dir)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
localError(info, "invalid path: " & p)
|
localError(conf, info, "invalid path: " & p)
|
||||||
result = 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 path = if path[0] == '"': strutils.unescape(path) else: path
|
||||||
let basedir = info.toFullPath().splitFile().dir
|
let basedir = info.toFullPath().splitFile().dir
|
||||||
let p = if os.isAbsolute(path) or '$' in path:
|
let p = if os.isAbsolute(path) or '$' in path:
|
||||||
|
|
@ -310,66 +302,69 @@ proc processCfgPath(path: string, info: TLineInfo): string =
|
||||||
else:
|
else:
|
||||||
basedir / path
|
basedir / path
|
||||||
try:
|
try:
|
||||||
result = pathSubs(p, basedir)
|
result = pathSubs(conf, p, basedir)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
localError(info, "invalid path: " & p)
|
localError(conf, info, "invalid path: " & p)
|
||||||
result = 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(',')
|
var a = arg.split(',')
|
||||||
if a.len != 4: localError(info, errTokenExpected,
|
if a.len != 4: localError(conf, info,
|
||||||
"DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN")
|
"DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected")
|
||||||
var line, column: int
|
var line, column: int
|
||||||
if parseUtils.parseInt(a[2], line) <= 0:
|
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:
|
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:
|
if dirtyOriginalIdx.int32 >= 0:
|
||||||
msgs.setDirtyFile(dirtyOriginalIdx, a[0])
|
msgs.setDirtyFile(dirtyOriginalIdx, a[0])
|
||||||
|
|
||||||
gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
|
gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
|
||||||
|
|
||||||
proc track(arg: string, info: TLineInfo) =
|
proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
|
||||||
var a = arg.split(',')
|
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
|
var line, column: int
|
||||||
if parseUtils.parseInt(a[1], line) <= 0:
|
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:
|
if parseUtils.parseInt(a[2], column) <= 0:
|
||||||
localError(info, errInvalidNumber, a[2])
|
localError(conf, info, errInvalidNumber % a[2])
|
||||||
gTrackPos = newLineInfo(a[0], line, column)
|
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}:
|
if pass in {passCmd2, passPP}:
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
options.inclDynlibOverride(arg)
|
options.inclDynlibOverride(conf, arg)
|
||||||
|
|
||||||
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
config: ConfigRef) =
|
conf: ConfigRef) =
|
||||||
var
|
var
|
||||||
theOS: TSystemOS
|
theOS: TSystemOS
|
||||||
cpu: TSystemCPU
|
cpu: TSystemCPU
|
||||||
key, val: string
|
key, val: string
|
||||||
case switch.normalize
|
case switch.normalize
|
||||||
of "path", "p":
|
of "path", "p":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
addPath(if pass == passPP: processCfgPath(arg, info) else: processPath(arg, info), info)
|
addPath(conf, if pass == passPP: processCfgPath(conf, arg, info) else: processPath(conf, arg, info), info)
|
||||||
of "nimblepath", "babelpath":
|
of "nimblepath", "babelpath":
|
||||||
# keep the old name for compat
|
# keep the old name for compat
|
||||||
if pass in {passCmd2, passPP} and not options.gNoNimblePath:
|
if pass in {passCmd2, passPP} and not options.gNoNimblePath:
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
var path = processPath(arg, info, notRelativeToProj=true)
|
var path = processPath(conf, arg, info, notRelativeToProj=true)
|
||||||
let nimbleDir = getEnv("NIMBLE_DIR")
|
let nimbleDir = getEnv("NIMBLE_DIR")
|
||||||
if nimbleDir.len > 0 and pass == passPP: path = nimbleDir / "pkgs"
|
if nimbleDir.len > 0 and pass == passPP: path = nimbleDir / "pkgs"
|
||||||
nimblePath(path, info)
|
nimblePath(conf, path, info)
|
||||||
of "nonimblepath", "nobabelpath":
|
of "nonimblepath", "nobabelpath":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
disableNimblePath()
|
disableNimblePath(conf)
|
||||||
of "excludepath":
|
of "excludepath":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
let path = processPath(arg, info)
|
let path = processPath(conf, arg, info)
|
||||||
|
|
||||||
options.searchPaths.keepItIf(cmpPaths(it, path) != 0)
|
options.searchPaths.keepItIf(cmpPaths(it, path) != 0)
|
||||||
options.lazyPaths.keepItIf(cmpPaths(it, path) != 0)
|
options.lazyPaths.keepItIf(cmpPaths(it, path) != 0)
|
||||||
|
|
@ -379,156 +374,156 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
options.searchPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
|
options.searchPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
|
||||||
options.lazyPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
|
options.lazyPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
|
||||||
of "nimcache":
|
of "nimcache":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
options.nimcacheDir = processPath(arg, info, true)
|
options.nimcacheDir = processPath(conf, arg, info, true)
|
||||||
of "out", "o":
|
of "out", "o":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
options.outFile = arg
|
options.outFile = arg
|
||||||
of "docseesrcurl":
|
of "docseesrcurl":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
options.docSeeSrcUrl = arg
|
options.docSeeSrcUrl = arg
|
||||||
of "mainmodule", "m":
|
of "mainmodule", "m":
|
||||||
discard "allow for backwards compatibility, but don't do anything"
|
discard "allow for backwards compatibility, but don't do anything"
|
||||||
of "define", "d":
|
of "define", "d":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if {':', '='} in arg:
|
if {':', '='} in arg:
|
||||||
splitSwitch(arg, key, val, pass, info)
|
splitSwitch(conf, arg, key, val, pass, info)
|
||||||
defineSymbol(key, val)
|
defineSymbol(conf.symbols, key, val)
|
||||||
else:
|
else:
|
||||||
defineSymbol(arg)
|
defineSymbol(conf.symbols, arg)
|
||||||
of "undef", "u":
|
of "undef", "u":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
undefSymbol(arg)
|
undefSymbol(conf.symbols, arg)
|
||||||
of "symbol":
|
of "symbol":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
# deprecated, do nothing
|
# deprecated, do nothing
|
||||||
of "compile":
|
of "compile":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: processCompile(arg)
|
if pass in {passCmd2, passPP}: processCompile(conf, arg)
|
||||||
of "link":
|
of "link":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: addExternalFileToLink(arg)
|
if pass in {passCmd2, passPP}: addExternalFileToLink(conf, arg)
|
||||||
of "debuginfo":
|
of "debuginfo":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optCDebug)
|
incl(gGlobalOptions, optCDebug)
|
||||||
of "embedsrc":
|
of "embedsrc":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optEmbedOrigSrc)
|
incl(gGlobalOptions, optEmbedOrigSrc)
|
||||||
of "compileonly", "c":
|
of "compileonly", "c":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optCompileOnly)
|
incl(gGlobalOptions, optCompileOnly)
|
||||||
of "nolinking":
|
of "nolinking":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optNoLinking)
|
incl(gGlobalOptions, optNoLinking)
|
||||||
of "nomain":
|
of "nomain":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optNoMain)
|
incl(gGlobalOptions, optNoMain)
|
||||||
of "forcebuild", "f":
|
of "forcebuild", "f":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optForceFullMake)
|
incl(gGlobalOptions, optForceFullMake)
|
||||||
of "project":
|
of "project":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
gWholeProject = true
|
gWholeProject = true
|
||||||
of "gc":
|
of "gc":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "boehm":
|
of "boehm":
|
||||||
gSelectedGC = gcBoehm
|
gSelectedGC = gcBoehm
|
||||||
defineSymbol("boehmgc")
|
defineSymbol(conf.symbols, "boehmgc")
|
||||||
of "refc":
|
of "refc":
|
||||||
gSelectedGC = gcRefc
|
gSelectedGC = gcRefc
|
||||||
of "v2":
|
of "v2":
|
||||||
gSelectedGC = gcV2
|
gSelectedGC = gcV2
|
||||||
of "markandsweep":
|
of "markandsweep":
|
||||||
gSelectedGC = gcMarkAndSweep
|
gSelectedGC = gcMarkAndSweep
|
||||||
defineSymbol("gcmarkandsweep")
|
defineSymbol(conf.symbols, "gcmarkandsweep")
|
||||||
of "generational":
|
of "generational":
|
||||||
gSelectedGC = gcGenerational
|
gSelectedGC = gcGenerational
|
||||||
defineSymbol("gcgenerational")
|
defineSymbol(conf.symbols, "gcgenerational")
|
||||||
of "go":
|
of "go":
|
||||||
gSelectedGC = gcGo
|
gSelectedGC = gcGo
|
||||||
defineSymbol("gogc")
|
defineSymbol(conf.symbols, "gogc")
|
||||||
of "none":
|
of "none":
|
||||||
gSelectedGC = gcNone
|
gSelectedGC = gcNone
|
||||||
defineSymbol("nogc")
|
defineSymbol(conf.symbols, "nogc")
|
||||||
of "stack", "regions":
|
of "stack", "regions":
|
||||||
gSelectedGC= gcRegions
|
gSelectedGC= gcRegions
|
||||||
defineSymbol("gcregions")
|
defineSymbol(conf.symbols, "gcregions")
|
||||||
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||||
of "warnings", "w":
|
of "warnings", "w":
|
||||||
if processOnOffSwitchOrList({optWarns}, arg, pass, info): listWarnings()
|
if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf)
|
||||||
of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
|
of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf)
|
||||||
of "hint": processSpecificNote(arg, wHint, pass, info, switch)
|
of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf)
|
||||||
of "hints":
|
of "hints":
|
||||||
if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints()
|
if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf)
|
||||||
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
|
of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info)
|
||||||
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
|
of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info)
|
||||||
of "excessivestacktrace": processOnOffSwitchG({optExcessiveStackTrace}, arg, pass, info)
|
of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info)
|
||||||
of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
|
of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info)
|
||||||
of "debugger":
|
of "debugger":
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "on", "endb":
|
of "on", "endb":
|
||||||
gOptions.incl optEndb
|
gOptions.incl optEndb
|
||||||
defineSymbol("endb")
|
defineSymbol(conf.symbols, "endb")
|
||||||
of "off":
|
of "off":
|
||||||
gOptions.excl optEndb
|
gOptions.excl optEndb
|
||||||
undefSymbol("endb")
|
undefSymbol(conf.symbols, "endb")
|
||||||
of "native", "gdb":
|
of "native", "gdb":
|
||||||
incl(gGlobalOptions, optCDebug)
|
incl(gGlobalOptions, optCDebug)
|
||||||
gOptions = gOptions + {optLineDir} - {optEndb}
|
gOptions = gOptions + {optLineDir} - {optEndb}
|
||||||
defineSymbol("nimTypeNames", nil) # type names are used in gdb pretty printing
|
defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
|
||||||
undefSymbol("endb")
|
undefSymbol(conf.symbols, "endb")
|
||||||
else:
|
else:
|
||||||
localError(info, "expected endb|gdb but found " & arg)
|
localError(conf, info, "expected endb|gdb but found " & arg)
|
||||||
of "profiler":
|
of "profiler":
|
||||||
processOnOffSwitch({optProfiler}, arg, pass, info)
|
processOnOffSwitch(conf, {optProfiler}, arg, pass, info)
|
||||||
if optProfiler in gOptions: defineSymbol("profiler")
|
if optProfiler in gOptions: defineSymbol(conf.symbols, "profiler")
|
||||||
else: undefSymbol("profiler")
|
else: undefSymbol(conf.symbols, "profiler")
|
||||||
of "memtracker":
|
of "memtracker":
|
||||||
processOnOffSwitch({optMemTracker}, arg, pass, info)
|
processOnOffSwitch(conf, {optMemTracker}, arg, pass, info)
|
||||||
if optMemTracker in gOptions: defineSymbol("memtracker")
|
if optMemTracker in gOptions: defineSymbol(conf.symbols, "memtracker")
|
||||||
else: undefSymbol("memtracker")
|
else: undefSymbol(conf.symbols, "memtracker")
|
||||||
of "hotcodereloading":
|
of "hotcodereloading":
|
||||||
processOnOffSwitch({optHotCodeReloading}, arg, pass, info)
|
processOnOffSwitch(conf, {optHotCodeReloading}, arg, pass, info)
|
||||||
if optHotCodeReloading in gOptions: defineSymbol("hotcodereloading")
|
if optHotCodeReloading in gOptions: defineSymbol(conf.symbols, "hotcodereloading")
|
||||||
else: undefSymbol("hotcodereloading")
|
else: undefSymbol(conf.symbols, "hotcodereloading")
|
||||||
of "oldnewlines":
|
of "oldnewlines":
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "on":
|
of "on":
|
||||||
options.gOldNewlines = true
|
options.gOldNewlines = true
|
||||||
defineSymbol("nimOldNewlines")
|
defineSymbol(conf.symbols, "nimOldNewlines")
|
||||||
of "off":
|
of "off":
|
||||||
options.gOldNewlines = false
|
options.gOldNewlines = false
|
||||||
undefSymbol("nimOldNewlines")
|
undefSymbol(conf.symbols, "nimOldNewlines")
|
||||||
else:
|
else:
|
||||||
localError(info, errOnOrOffExpectedButXFound, arg)
|
localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
||||||
of "laxstrings": processOnOffSwitch({optLaxStrings}, arg, pass, info)
|
of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info)
|
||||||
of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
|
of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
|
||||||
of "floatchecks":
|
of "floatchecks":
|
||||||
processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
|
processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
|
||||||
of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info)
|
of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info)
|
||||||
of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info)
|
of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info)
|
||||||
of "nilchecks": processOnOffSwitch({optNilCheck}, arg, pass, info)
|
of "nilchecks": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info)
|
||||||
of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info)
|
of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info)
|
||||||
of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info)
|
of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info)
|
||||||
of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info)
|
of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info)
|
||||||
of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info)
|
of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info)
|
||||||
of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info)
|
of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info)
|
||||||
of "movechecks": processOnOffSwitch({optMoveCheck}, arg, pass, info)
|
of "movechecks": processOnOffSwitch(conf, {optMoveCheck}, arg, pass, info)
|
||||||
of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
|
of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info)
|
||||||
of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
|
of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info)
|
||||||
of "deadcodeelim": discard # deprecated, dead code elim always on
|
of "deadcodeelim": discard # deprecated, dead code elim always on
|
||||||
of "threads":
|
of "threads":
|
||||||
processOnOffSwitchG({optThreads}, arg, pass, info)
|
processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
|
||||||
#if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
|
#if optThreads in gGlobalOptions: incl(conf.notes, warnGcUnsafe)
|
||||||
of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
|
of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
|
||||||
of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
|
of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info)
|
||||||
of "implicitstatic":
|
of "implicitstatic":
|
||||||
processOnOffSwitch({optImplicitStatic}, arg, pass, info)
|
processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
|
||||||
of "patterns":
|
of "patterns":
|
||||||
processOnOffSwitch({optPatterns}, arg, pass, info)
|
processOnOffSwitch(conf, {optPatterns}, arg, pass, info)
|
||||||
of "opt":
|
of "opt":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "speed":
|
of "speed":
|
||||||
incl(gOptions, optOptimizeSpeed)
|
incl(gOptions, optOptimizeSpeed)
|
||||||
|
|
@ -539,99 +534,99 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
of "none":
|
of "none":
|
||||||
excl(gOptions, optOptimizeSpeed)
|
excl(gOptions, optOptimizeSpeed)
|
||||||
excl(gOptions, optOptimizeSize)
|
excl(gOptions, optOptimizeSize)
|
||||||
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
|
else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
|
||||||
of "app":
|
of "app":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "gui":
|
of "gui":
|
||||||
incl(gGlobalOptions, optGenGuiApp)
|
incl(gGlobalOptions, optGenGuiApp)
|
||||||
defineSymbol("executable")
|
defineSymbol(conf.symbols, "executable")
|
||||||
defineSymbol("guiapp")
|
defineSymbol(conf.symbols, "guiapp")
|
||||||
of "console":
|
of "console":
|
||||||
excl(gGlobalOptions, optGenGuiApp)
|
excl(gGlobalOptions, optGenGuiApp)
|
||||||
defineSymbol("executable")
|
defineSymbol(conf.symbols, "executable")
|
||||||
defineSymbol("consoleapp")
|
defineSymbol(conf.symbols, "consoleapp")
|
||||||
of "lib":
|
of "lib":
|
||||||
incl(gGlobalOptions, optGenDynLib)
|
incl(gGlobalOptions, optGenDynLib)
|
||||||
excl(gGlobalOptions, optGenGuiApp)
|
excl(gGlobalOptions, optGenGuiApp)
|
||||||
defineSymbol("library")
|
defineSymbol(conf.symbols, "library")
|
||||||
defineSymbol("dll")
|
defineSymbol(conf.symbols, "dll")
|
||||||
of "staticlib":
|
of "staticlib":
|
||||||
incl(gGlobalOptions, optGenStaticLib)
|
incl(gGlobalOptions, optGenStaticLib)
|
||||||
excl(gGlobalOptions, optGenGuiApp)
|
excl(gGlobalOptions, optGenGuiApp)
|
||||||
defineSymbol("library")
|
defineSymbol(conf.symbols, "library")
|
||||||
defineSymbol("staticlib")
|
defineSymbol(conf.symbols, "staticlib")
|
||||||
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
|
else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
|
||||||
of "passc", "t":
|
of "passc", "t":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(arg)
|
if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(conf, arg)
|
||||||
of "passl", "l":
|
of "passl", "l":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(arg)
|
if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg)
|
||||||
of "cincludes":
|
of "cincludes":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info)
|
if pass in {passCmd2, passPP}: cIncludes.add processPath(conf, arg, info)
|
||||||
of "clibdir":
|
of "clibdir":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: cLibs.add arg.processPath(info)
|
if pass in {passCmd2, passPP}: cLibs.add processPath(conf, arg, info)
|
||||||
of "clib":
|
of "clib":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
|
if pass in {passCmd2, passPP}: cLinkedLibs.add processPath(conf, arg, info)
|
||||||
of "header":
|
of "header":
|
||||||
if config != nil: config.headerFile = arg
|
if conf != nil: conf.headerFile = arg
|
||||||
incl(gGlobalOptions, optGenIndex)
|
incl(gGlobalOptions, optGenIndex)
|
||||||
of "index":
|
of "index":
|
||||||
processOnOffSwitchG({optGenIndex}, arg, pass, info)
|
processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info)
|
||||||
of "import":
|
of "import":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: implicitImports.add arg
|
if pass in {passCmd2, passPP}: implicitImports.add arg
|
||||||
of "include":
|
of "include":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: implicitIncludes.add arg
|
if pass in {passCmd2, passPP}: implicitIncludes.add arg
|
||||||
of "listcmd":
|
of "listcmd":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optListCmd)
|
incl(gGlobalOptions, optListCmd)
|
||||||
of "genmapping":
|
of "genmapping":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optGenMapping)
|
incl(gGlobalOptions, optGenMapping)
|
||||||
of "os":
|
of "os":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd1, passPP}:
|
if pass in {passCmd1, passPP}:
|
||||||
theOS = platform.nameToOS(arg)
|
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:
|
elif theOS != platform.hostOS:
|
||||||
setTarget(theOS, targetCPU)
|
setTarget(theOS, targetCPU)
|
||||||
of "cpu":
|
of "cpu":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if pass in {passCmd1, passPP}:
|
if pass in {passCmd1, passPP}:
|
||||||
cpu = platform.nameToCPU(arg)
|
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:
|
elif cpu != platform.hostCPU:
|
||||||
setTarget(targetOS, cpu)
|
setTarget(targetOS, cpu)
|
||||||
of "run", "r":
|
of "run", "r":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optRun)
|
incl(gGlobalOptions, optRun)
|
||||||
of "verbosity":
|
of "verbosity":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
gVerbosity = parseInt(arg)
|
gVerbosity = parseInt(arg)
|
||||||
gNotes = NotesVerbosity[gVerbosity]
|
conf.notes = NotesVerbosity[gVerbosity]
|
||||||
incl(gNotes, enableNotes)
|
incl(conf.notes, conf.enableNotes)
|
||||||
excl(gNotes, disableNotes)
|
excl(conf.notes, conf.disableNotes)
|
||||||
gMainPackageNotes = gNotes
|
conf.mainPackageNotes = conf.notes
|
||||||
of "parallelbuild":
|
of "parallelbuild":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
gNumberOfProcessors = parseInt(arg)
|
gNumberOfProcessors = parseInt(arg)
|
||||||
of "version", "v":
|
of "version", "v":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
writeVersionInfo(pass)
|
writeVersionInfo(pass)
|
||||||
of "advanced":
|
of "advanced":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
writeAdvancedUsage(pass)
|
writeAdvancedUsage(pass)
|
||||||
of "fullhelp":
|
of "fullhelp":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
writeFullhelp(pass)
|
writeFullhelp(pass)
|
||||||
of "help", "h":
|
of "help", "h":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
helpOnError(pass)
|
helpOnError(pass)
|
||||||
of "symbolfiles":
|
of "symbolfiles":
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
|
|
@ -640,101 +635,103 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
of "writeonly": gSymbolFiles = writeOnlySf
|
of "writeonly": gSymbolFiles = writeOnlySf
|
||||||
of "readonly": gSymbolFiles = readOnlySf
|
of "readonly": gSymbolFiles = readOnlySf
|
||||||
of "v2": gSymbolFiles = v2Sf
|
of "v2": gSymbolFiles = v2Sf
|
||||||
else: localError(info, errOnOrOffExpectedButXFound, arg)
|
else: localError(conf, info, "invalid option for --symbolFiles: " & arg)
|
||||||
of "skipcfg":
|
of "skipcfg":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optSkipConfigFile)
|
incl(gGlobalOptions, optSkipConfigFile)
|
||||||
of "skipprojcfg":
|
of "skipprojcfg":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optSkipProjConfigFile)
|
incl(gGlobalOptions, optSkipProjConfigFile)
|
||||||
of "skipusercfg":
|
of "skipusercfg":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optSkipUserConfigFile)
|
incl(gGlobalOptions, optSkipUserConfigFile)
|
||||||
of "skipparentcfg":
|
of "skipparentcfg":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optSkipParentConfigFiles)
|
incl(gGlobalOptions, optSkipParentConfigFiles)
|
||||||
of "genscript", "gendeps":
|
of "genscript", "gendeps":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optGenScript)
|
incl(gGlobalOptions, optGenScript)
|
||||||
incl(gGlobalOptions, optCompileOnly)
|
incl(gGlobalOptions, optCompileOnly)
|
||||||
of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info)
|
of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info)
|
||||||
of "lib":
|
of "lib":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
libpath = processPath(arg, info, notRelativeToProj=true)
|
libpath = processPath(conf, arg, info, notRelativeToProj=true)
|
||||||
of "putenv":
|
of "putenv":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
splitSwitch(arg, key, val, pass, info)
|
splitSwitch(conf, arg, key, val, pass, info)
|
||||||
os.putEnv(key, val)
|
os.putEnv(key, val)
|
||||||
of "cc":
|
of "cc":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
setCC(arg)
|
setCC(conf, arg, info)
|
||||||
of "track":
|
of "track":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
track(arg, info)
|
track(conf, arg, info)
|
||||||
of "trackdirty":
|
of "trackdirty":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
trackDirty(arg, info)
|
trackDirty(conf, arg, info)
|
||||||
of "suggest":
|
of "suggest":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
gIdeCmd = ideSug
|
gIdeCmd = ideSug
|
||||||
of "def":
|
of "def":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
gIdeCmd = ideDef
|
gIdeCmd = ideDef
|
||||||
of "eval":
|
of "eval":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
gEvalExpr = arg
|
gEvalExpr = arg
|
||||||
of "context":
|
of "context":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
gIdeCmd = ideCon
|
gIdeCmd = ideCon
|
||||||
of "usages":
|
of "usages":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
gIdeCmd = ideUse
|
gIdeCmd = ideUse
|
||||||
of "stdout":
|
of "stdout":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optStdout)
|
incl(gGlobalOptions, optStdout)
|
||||||
of "listfullpaths":
|
of "listfullpaths":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
gListFullPaths = true
|
gListFullPaths = true
|
||||||
of "dynliboverride":
|
of "dynliboverride":
|
||||||
dynlibOverride(switch, arg, pass, info)
|
dynlibOverride(conf, switch, arg, pass, info)
|
||||||
of "dynliboverrideall":
|
of "dynliboverrideall":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
gDynlibOverrideAll = true
|
gDynlibOverrideAll = true
|
||||||
of "cs":
|
of "cs":
|
||||||
# only supported for compatibility. Does nothing.
|
# only supported for compatibility. Does nothing.
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
of "experimental":
|
of "experimental":
|
||||||
if arg.len == 0:
|
if arg.len == 0:
|
||||||
config.features.incl oldExperimentalFeatures
|
conf.features.incl oldExperimentalFeatures
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
config.features.incl parseEnum[Feature](arg)
|
conf.features.incl parseEnum[Feature](arg)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
localError(info, "unknown experimental feature")
|
localError(conf, info, "unknown experimental feature")
|
||||||
of "nocppexceptions":
|
of "nocppexceptions":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optNoCppExceptions)
|
incl(gGlobalOptions, optNoCppExceptions)
|
||||||
defineSymbol("noCppExceptions")
|
defineSymbol(conf.symbols, "noCppExceptions")
|
||||||
of "cppdefine":
|
of "cppdefine":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
if config != nil:
|
if conf != nil:
|
||||||
config.cppDefine(arg)
|
conf.cppDefine(arg)
|
||||||
of "newruntime":
|
of "newruntime":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
doAssert(config != nil)
|
doAssert(conf != nil)
|
||||||
incl(config.features, destructor)
|
incl(conf.features, destructor)
|
||||||
defineSymbol("nimNewRuntime")
|
defineSymbol(conf.symbols, "nimNewRuntime")
|
||||||
of "cppcompiletonamespace":
|
of "cppcompiletonamespace":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
useNimNamespace = true
|
useNimNamespace = true
|
||||||
defineSymbol("cppCompileToNamespace")
|
defineSymbol(conf.symbols, "cppCompileToNamespace")
|
||||||
else:
|
else:
|
||||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
|
||||||
else: invalidCmdLineOption(pass, switch, info)
|
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
|
var cmd, arg: string
|
||||||
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
|
splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
|
||||||
processSwitch(cmd, arg, pass, gCmdLineInfo, config)
|
processSwitch(cmd, arg, pass, gCmdLineInfo, config)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,77 +12,30 @@
|
||||||
import
|
import
|
||||||
strtabs, platform, strutils, idents
|
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
|
const
|
||||||
catNone = "false"
|
catNone = "false"
|
||||||
|
|
||||||
proc defineSymbol*(symbol: string, value: string = "true") =
|
proc defineSymbol*(symbols: StringTableRef; symbol: string, value: string = "true") =
|
||||||
gSymbols[symbol] = value
|
symbols[symbol] = value
|
||||||
|
|
||||||
proc undefSymbol*(symbol: string) =
|
proc undefSymbol*(symbols: StringTableRef; symbol: string) =
|
||||||
gSymbols[symbol] = catNone
|
symbols[symbol] = catNone
|
||||||
|
|
||||||
proc isDefined*(symbol: string): bool =
|
#proc lookupSymbol*(symbols: StringTableRef; symbol: string): string =
|
||||||
if gSymbols.hasKey(symbol):
|
# result = if isDefined(symbol): gSymbols[symbol] else: nil
|
||||||
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 isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
|
iterator definedSymbolNames*(symbols: StringTableRef): string =
|
||||||
|
for key, val in pairs(symbols):
|
||||||
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):
|
|
||||||
if val != catNone: yield key
|
if val != catNone: yield key
|
||||||
|
|
||||||
proc countDefinedSymbols*(): int =
|
proc countDefinedSymbols*(symbols: StringTableRef): int =
|
||||||
result = 0
|
result = 0
|
||||||
for key, val in pairs(gSymbols):
|
for key, val in pairs(symbols):
|
||||||
if val != catNone: inc(result)
|
if val != catNone: inc(result)
|
||||||
|
|
||||||
proc initDefines*() =
|
proc initDefines*(symbols: StringTableRef) =
|
||||||
gSymbols = newStringTable(modeStyleInsensitive)
|
|
||||||
# for bootstrapping purposes and old code:
|
# for bootstrapping purposes and old code:
|
||||||
|
template defineSymbol(s) = symbols.defineSymbol(s)
|
||||||
defineSymbol("nimhygiene")
|
defineSymbol("nimhygiene")
|
||||||
defineSymbol("niminheritable")
|
defineSymbol("niminheritable")
|
||||||
defineSymbol("nimmixin")
|
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
|
import
|
||||||
ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
||||||
std / sha1, streams
|
configuration, std / sha1, streams
|
||||||
|
|
||||||
#from debuginfo import writeDebugInfo
|
#from debuginfo import writeDebugInfo
|
||||||
|
|
||||||
|
|
@ -376,7 +376,7 @@ proc nameToCC*(name: string): TSystemCC =
|
||||||
return i
|
return i
|
||||||
result = ccNone
|
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
|
# use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
|
||||||
# for niminst support
|
# for niminst support
|
||||||
let fullSuffix =
|
let fullSuffix =
|
||||||
|
|
@ -394,62 +394,63 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
|
||||||
let fullCCname = platform.CPU[targetCPU].name & '.' &
|
let fullCCname = platform.CPU[targetCPU].name & '.' &
|
||||||
platform.OS[targetOS].name & '.' &
|
platform.OS[targetOS].name & '.' &
|
||||||
CC[c].name & fullSuffix
|
CC[c].name & fullSuffix
|
||||||
result = getConfigVar(fullCCname)
|
result = getConfigVar(conf, fullCCname)
|
||||||
if result.len == 0:
|
if result.len == 0:
|
||||||
# not overriden for this cross compilation setting?
|
# not overriden for this cross compilation setting?
|
||||||
result = getConfigVar(CC[c].name & fullSuffix)
|
result = getConfigVar(conf, CC[c].name & fullSuffix)
|
||||||
else:
|
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)
|
cCompiler = nameToCC(ccname)
|
||||||
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
|
if cCompiler == ccNone:
|
||||||
compileOptions = getConfigVar(cCompiler, ".options.always")
|
localError(conf, info, "unknown C compiler: '$1'" % ccname)
|
||||||
|
compileOptions = getConfigVar(conf, cCompiler, ".options.always")
|
||||||
linkOptions = ""
|
linkOptions = ""
|
||||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
ccompilerpath = getConfigVar(conf, cCompiler, ".path")
|
||||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
|
||||||
defineSymbol(CC[cCompiler].name)
|
defineSymbol(conf.symbols, CC[cCompiler].name)
|
||||||
|
|
||||||
proc addOpt(dest: var string, src: string) =
|
proc addOpt(dest: var string, src: string) =
|
||||||
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
|
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
|
||||||
add(dest, src)
|
add(dest, src)
|
||||||
|
|
||||||
proc addLinkOption*(option: string) =
|
proc addLinkOption*(conf: ConfigRef; option: string) =
|
||||||
addOpt(linkOptions, option)
|
addOpt(linkOptions, option)
|
||||||
|
|
||||||
proc addCompileOption*(option: string) =
|
proc addCompileOption*(conf: ConfigRef; option: string) =
|
||||||
if strutils.find(compileOptions, option, 0) < 0:
|
if strutils.find(compileOptions, option, 0) < 0:
|
||||||
addOpt(compileOptions, option)
|
addOpt(compileOptions, option)
|
||||||
|
|
||||||
proc addLinkOptionCmd*(option: string) =
|
proc addLinkOptionCmd*(conf: ConfigRef; option: string) =
|
||||||
addOpt(linkOptionsCmd, option)
|
addOpt(linkOptionsCmd, option)
|
||||||
|
|
||||||
proc addCompileOptionCmd*(option: string) =
|
proc addCompileOptionCmd*(conf: ConfigRef; option: string) =
|
||||||
compileOptionsCmd.add(option)
|
compileOptionsCmd.add(option)
|
||||||
|
|
||||||
proc initVars*() =
|
proc initVars*(conf: ConfigRef) =
|
||||||
# we need to define the symbol here, because ``CC`` may have never been set!
|
# 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)
|
for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
|
||||||
defineSymbol(CC[cCompiler].name)
|
defineSymbol(conf.symbols, CC[cCompiler].name)
|
||||||
addCompileOption(getConfigVar(cCompiler, ".options.always"))
|
addCompileOption(conf, getConfigVar(conf, cCompiler, ".options.always"))
|
||||||
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
||||||
if len(ccompilerpath) == 0:
|
if len(ccompilerpath) == 0:
|
||||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
ccompilerpath = getConfigVar(conf, cCompiler, ".path")
|
||||||
|
|
||||||
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
|
proc completeCFilePath*(conf: ConfigRef; cfile: string, createSubDir: bool = true): string =
|
||||||
result = completeGeneratedFilePath(cfile, createSubDir)
|
result = completeGeneratedFilePath(conf, cfile, createSubDir)
|
||||||
|
|
||||||
proc toObjFile*(filename: string): string =
|
proc toObjFile*(conf: ConfigRef; filename: string): string =
|
||||||
# Object file for compilation
|
# Object file for compilation
|
||||||
#if filename.endsWith(".cpp"):
|
#if filename.endsWith(".cpp"):
|
||||||
# result = changeFileExt(filename, "cpp." & CC[cCompiler].objExt)
|
# result = changeFileExt(filename, "cpp." & CC[cCompiler].objExt)
|
||||||
#else:
|
#else:
|
||||||
result = changeFileExt(filename, CC[cCompiler].objExt)
|
result = changeFileExt(filename, CC[cCompiler].objExt)
|
||||||
|
|
||||||
proc addFileToCompile*(cf: Cfile) =
|
proc addFileToCompile*(conf: ConfigRef; cf: Cfile) =
|
||||||
toCompile.add(cf)
|
toCompile.add(cf)
|
||||||
|
|
||||||
proc resetCompilationLists* =
|
proc resetCompilationLists*(conf: ConfigRef) =
|
||||||
toCompile.setLen 0
|
toCompile.setLen 0
|
||||||
## XXX: we must associate these with their originating module
|
## XXX: we must associate these with their originating module
|
||||||
# when the module is loaded/unloaded it adds/removes its items
|
# 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?
|
# Maybe we can do that in checkDep on the other hand?
|
||||||
externalToLink.setLen 0
|
externalToLink.setLen 0
|
||||||
|
|
||||||
proc addExternalFileToLink*(filename: string) =
|
proc addExternalFileToLink*(conf: ConfigRef; filename: string) =
|
||||||
externalToLink.insert(filename, 0)
|
externalToLink.insert(filename, 0)
|
||||||
|
|
||||||
proc execWithEcho(cmd: string, msg = hintExecuting): int =
|
proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int =
|
||||||
rawMessage(msg, cmd)
|
rawMessage(conf, msg, cmd)
|
||||||
result = execCmd(cmd)
|
result = execCmd(cmd)
|
||||||
|
|
||||||
proc execExternalProgram*(cmd: string, msg = hintExecuting) =
|
proc execExternalProgram*(conf: ConfigRef; cmd: string, msg = hintExecuting) =
|
||||||
if execWithEcho(cmd, msg) != 0:
|
if execWithEcho(conf, cmd, msg) != 0:
|
||||||
rawMessage(errExecutionOfProgramFailed, cmd)
|
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)
|
let (dir, name, ext) = splitFile(projectFile)
|
||||||
writeRope(script, getNimcacheDir() / addFileExt("compile_" & name,
|
writeRope(script, getNimcacheDir(conf) / addFileExt("compile_" & name,
|
||||||
platform.OS[targetOS].scriptExt))
|
platform.OS[targetOS].scriptExt))
|
||||||
copyFile(libpath / "nimbase.h", getNimcacheDir() / "nimbase.h")
|
copyFile(libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h")
|
||||||
|
|
||||||
proc getOptSpeed(c: TSystemCC): string =
|
proc getOptSpeed(conf: ConfigRef; c: TSystemCC): string =
|
||||||
result = getConfigVar(c, ".options.speed")
|
result = getConfigVar(conf, c, ".options.speed")
|
||||||
if result == "":
|
if result == "":
|
||||||
result = CC[c].optSpeed # use default settings from this file
|
result = CC[c].optSpeed # use default settings from this file
|
||||||
|
|
||||||
proc getDebug(c: TSystemCC): string =
|
proc getDebug(conf: ConfigRef; c: TSystemCC): string =
|
||||||
result = getConfigVar(c, ".options.debug")
|
result = getConfigVar(conf, c, ".options.debug")
|
||||||
if result == "":
|
if result == "":
|
||||||
result = CC[c].debug # use default settings from this file
|
result = CC[c].debug # use default settings from this file
|
||||||
|
|
||||||
proc getOptSize(c: TSystemCC): string =
|
proc getOptSize(conf: ConfigRef; c: TSystemCC): string =
|
||||||
result = getConfigVar(c, ".options.size")
|
result = getConfigVar(conf, c, ".options.size")
|
||||||
if result == "":
|
if result == "":
|
||||||
result = CC[c].optSize # use default settings from this file
|
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
|
# We used to check current OS != specified OS, but this makes no sense
|
||||||
# really: Cross compilation from Linux to Linux for example is entirely
|
# really: Cross compilation from Linux to Linux for example is entirely
|
||||||
# reasonable.
|
# reasonable.
|
||||||
# `optGenMapping` is included here for niminst.
|
# `optGenMapping` is included here for niminst.
|
||||||
result = gGlobalOptions * {optGenScript, optGenMapping} != {}
|
result = gGlobalOptions * {optGenScript, optGenMapping} != {}
|
||||||
|
|
||||||
proc cFileSpecificOptions(cfilename: string): string =
|
proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string =
|
||||||
result = compileOptions
|
result = compileOptions
|
||||||
for option in compileOptionsCmd:
|
for option in compileOptionsCmd:
|
||||||
if strutils.find(result, option, 0) < 0:
|
if strutils.find(result, option, 0) < 0:
|
||||||
addOpt(result, option)
|
addOpt(result, option)
|
||||||
|
|
||||||
var trunk = splitFile(cfilename).name
|
let trunk = splitFile(cfilename).name
|
||||||
if optCDebug in gGlobalOptions:
|
if optCDebug in gGlobalOptions:
|
||||||
var key = trunk & ".debug"
|
let key = trunk & ".debug"
|
||||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
|
||||||
else: addOpt(result, getDebug(cCompiler))
|
else: addOpt(result, getDebug(conf, cCompiler))
|
||||||
if optOptimizeSpeed in gOptions:
|
if optOptimizeSpeed in gOptions:
|
||||||
var key = trunk & ".speed"
|
let key = trunk & ".speed"
|
||||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
|
||||||
else: addOpt(result, getOptSpeed(cCompiler))
|
else: addOpt(result, getOptSpeed(conf, cCompiler))
|
||||||
elif optOptimizeSize in gOptions:
|
elif optOptimizeSize in gOptions:
|
||||||
var key = trunk & ".size"
|
let key = trunk & ".size"
|
||||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
|
||||||
else: addOpt(result, getOptSize(cCompiler))
|
else: addOpt(result, getOptSize(conf, cCompiler))
|
||||||
var key = trunk & ".always"
|
let key = trunk & ".always"
|
||||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
|
||||||
|
|
||||||
proc getCompileOptions: string =
|
proc getCompileOptions(conf: ConfigRef): string =
|
||||||
result = cFileSpecificOptions("__dummy__")
|
result = cFileSpecificOptions(conf, "__dummy__")
|
||||||
|
|
||||||
proc getLinkOptions: string =
|
proc getLinkOptions(conf: ConfigRef): string =
|
||||||
result = linkOptions & " " & linkOptionsCmd & " "
|
result = linkOptions & " " & linkOptionsCmd & " "
|
||||||
for linkedLib in items(cLinkedLibs):
|
for linkedLib in items(cLinkedLibs):
|
||||||
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
|
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
|
||||||
for libDir in items(cLibs):
|
for libDir in items(cLibs):
|
||||||
result.add(join([CC[cCompiler].linkDirCmd, libDir.quoteShell]))
|
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
|
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
|
||||||
(platform.hostOS == osWindows)
|
(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"):
|
result = if gCmd == cmdCompileToCpp and not cfile.endsWith(".c"):
|
||||||
CC[compiler].cppCompiler
|
CC[compiler].cppCompiler
|
||||||
else:
|
else:
|
||||||
CC[compiler].compilerExe
|
CC[compiler].compilerExe
|
||||||
if result.len == 0:
|
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
|
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
|
||||||
elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
|
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 c = cCompiler
|
||||||
var options = cFileSpecificOptions(cfile.cname)
|
var options = cFileSpecificOptions(conf, cfile.cname)
|
||||||
var exe = getConfigVar(c, ".exe")
|
var exe = getConfigVar(conf, c, ".exe")
|
||||||
if exe.len == 0: exe = c.getCompilerExe(cfile.cname)
|
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
|
if optGenDynLib in gGlobalOptions and
|
||||||
ospNeedsPIC in platform.OS[targetOS].props:
|
ospNeedsPIC in platform.OS[targetOS].props:
|
||||||
add(options, ' ' & CC[c].pic)
|
add(options, ' ' & CC[c].pic)
|
||||||
|
|
||||||
var includeCmd, compilePattern: string
|
var includeCmd, compilePattern: string
|
||||||
if not noAbsolutePaths():
|
if not noAbsolutePaths(conf):
|
||||||
# compute include paths:
|
# compute include paths:
|
||||||
includeCmd = CC[c].includeCmd & quoteShell(libpath)
|
includeCmd = CC[c].includeCmd & quoteShell(libpath)
|
||||||
|
|
||||||
|
|
@ -567,18 +571,18 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
|
||||||
compilePattern = joinPath(ccompilerpath, exe)
|
compilePattern = joinPath(ccompilerpath, exe)
|
||||||
else:
|
else:
|
||||||
includeCmd = ""
|
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
|
else: cfile.cname
|
||||||
|
|
||||||
var objfile =
|
var objfile =
|
||||||
if cfile.obj.len == 0:
|
if cfile.obj.len == 0:
|
||||||
if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths():
|
if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(conf):
|
||||||
toObjFile(cf)
|
toObjFile(conf, cf)
|
||||||
else:
|
else:
|
||||||
completeCFilePath(toObjFile(cf))
|
completeCFilePath(conf, toObjFile(conf, cf))
|
||||||
elif noAbsolutePaths():
|
elif noAbsolutePaths(conf):
|
||||||
extractFilename(cfile.obj)
|
extractFilename(cfile.obj)
|
||||||
else:
|
else:
|
||||||
cfile.obj
|
cfile.obj
|
||||||
|
|
@ -587,30 +591,30 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
|
||||||
cf = quoteShell(cf)
|
cf = quoteShell(cf)
|
||||||
result = quoteShell(compilePattern % [
|
result = quoteShell(compilePattern % [
|
||||||
"file", cf, "objfile", objfile, "options", options,
|
"file", cf, "objfile", objfile, "options", options,
|
||||||
"include", includeCmd, "nim", getPrefixDir(),
|
"include", includeCmd, "nim", getPrefixDir(conf),
|
||||||
"nim", getPrefixDir(), "lib", libpath])
|
"nim", getPrefixDir(conf), "lib", libpath])
|
||||||
add(result, ' ')
|
add(result, ' ')
|
||||||
addf(result, CC[c].compileTmpl, [
|
addf(result, CC[c].compileTmpl, [
|
||||||
"file", cf, "objfile", objfile,
|
"file", cf, "objfile", objfile,
|
||||||
"options", options, "include", includeCmd,
|
"options", options, "include", includeCmd,
|
||||||
"nim", quoteShell(getPrefixDir()),
|
"nim", quoteShell(getPrefixDir(conf)),
|
||||||
"nim", quoteShell(getPrefixDir()),
|
"nim", quoteShell(getPrefixDir(conf)),
|
||||||
"lib", quoteShell(libpath)])
|
"lib", quoteShell(libpath)])
|
||||||
|
|
||||||
proc footprint(cfile: Cfile): SecureHash =
|
proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
|
||||||
result = secureHash(
|
result = secureHash(
|
||||||
$secureHashFile(cfile.cname) &
|
$secureHashFile(cfile.cname) &
|
||||||
platform.OS[targetOS].name &
|
platform.OS[targetOS].name &
|
||||||
platform.CPU[targetCPU].name &
|
platform.CPU[targetCPU].name &
|
||||||
extccomp.CC[extccomp.cCompiler].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}:
|
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
var hashFile = toGeneratedFile(cfile.cname.withPackageName, "sha1")
|
var hashFile = toGeneratedFile(conf, cfile.cname.withPackageName, "sha1")
|
||||||
var currentHash = footprint(cfile)
|
var currentHash = footprint(conf, cfile)
|
||||||
var f: File
|
var f: File
|
||||||
if open(f, hashFile, fmRead):
|
if open(f, hashFile, fmRead):
|
||||||
let oldHash = parseSecureHash(f.readLine())
|
let oldHash = parseSecureHash(f.readLine())
|
||||||
|
|
@ -623,23 +627,23 @@ proc externalFileChanged(cfile: Cfile): bool =
|
||||||
f.writeLine($currentHash)
|
f.writeLine($currentHash)
|
||||||
close(f)
|
close(f)
|
||||||
|
|
||||||
proc addExternalFileToCompile*(c: var Cfile) =
|
proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
|
||||||
if optForceFullMake notin gGlobalOptions and not externalFileChanged(c):
|
if optForceFullMake notin gGlobalOptions and not externalFileChanged(conf, c):
|
||||||
c.flags.incl CfileFlag.Cached
|
c.flags.incl CfileFlag.Cached
|
||||||
toCompile.add(c)
|
toCompile.add(c)
|
||||||
|
|
||||||
proc addExternalFileToCompile*(filename: string) =
|
proc addExternalFileToCompile*(conf: ConfigRef; filename: string) =
|
||||||
var c = Cfile(cname: filename,
|
var c = Cfile(cname: filename,
|
||||||
obj: toObjFile(completeCFilePath(changeFileExt(filename, ""), false)),
|
obj: toObjFile(conf, completeCFilePath(conf, changeFileExt(filename, ""), false)),
|
||||||
flags: {CfileFlag.External})
|
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) =
|
prettyCmds: var TStringSeq) =
|
||||||
for it in list:
|
for it in list:
|
||||||
# call the C compiler for the .c file:
|
# call the C compiler for the .c file:
|
||||||
if it.flags.contains(CfileFlag.Cached): continue
|
if it.flags.contains(CfileFlag.Cached): continue
|
||||||
var compileCmd = getCompileCFileCmd(it)
|
var compileCmd = getCompileCFileCmd(conf, it)
|
||||||
if optCompileOnly notin gGlobalOptions:
|
if optCompileOnly notin gGlobalOptions:
|
||||||
add(cmds, compileCmd)
|
add(cmds, compileCmd)
|
||||||
let (_, name, _) = splitFile(it.cname)
|
let (_, name, _) = splitFile(it.cname)
|
||||||
|
|
@ -648,7 +652,7 @@ proc compileCFile(list: CFileList, script: var Rope, cmds: var TStringSeq,
|
||||||
add(script, compileCmd)
|
add(script, compileCmd)
|
||||||
add(script, tnl)
|
add(script, tnl)
|
||||||
|
|
||||||
proc getLinkCmd(projectfile, objfiles: string): string =
|
proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
|
||||||
if optGenStaticLib in gGlobalOptions:
|
if optGenStaticLib in gGlobalOptions:
|
||||||
var libname: string
|
var libname: string
|
||||||
if options.outFile.len > 0:
|
if options.outFile.len > 0:
|
||||||
|
|
@ -660,11 +664,11 @@ proc getLinkCmd(projectfile, objfiles: string): string =
|
||||||
result = CC[cCompiler].buildLib % ["libfile", libname,
|
result = CC[cCompiler].buildLib % ["libfile", libname,
|
||||||
"objfiles", objfiles]
|
"objfiles", objfiles]
|
||||||
else:
|
else:
|
||||||
var linkerExe = getConfigVar(cCompiler, ".linkerexe")
|
var linkerExe = getConfigVar(conf, cCompiler, ".linkerexe")
|
||||||
if len(linkerExe) == 0: linkerExe = cCompiler.getLinkerExe
|
if len(linkerExe) == 0: linkerExe = getLinkerExe(conf, cCompiler)
|
||||||
# bug #6452: We must not use ``quoteShell`` here for ``linkerExe``
|
# bug #6452: We must not use ``quoteShell`` here for ``linkerExe``
|
||||||
if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
|
if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe")
|
||||||
if noAbsolutePaths(): result = linkerExe
|
if noAbsolutePaths(conf): result = linkerExe
|
||||||
else: result = joinPath(ccompilerpath, linkerExe)
|
else: result = joinPath(ccompilerpath, linkerExe)
|
||||||
let buildgui = if optGenGuiApp in gGlobalOptions: CC[cCompiler].buildGui
|
let buildgui = if optGenGuiApp in gGlobalOptions: CC[cCompiler].buildGui
|
||||||
else: ""
|
else: ""
|
||||||
|
|
@ -679,60 +683,63 @@ proc getLinkCmd(projectfile, objfiles: string): string =
|
||||||
exefile = options.outFile.expandTilde
|
exefile = options.outFile.expandTilde
|
||||||
if not exefile.isAbsolute():
|
if not exefile.isAbsolute():
|
||||||
exefile = getCurrentDir() / exefile
|
exefile = getCurrentDir() / exefile
|
||||||
if not noAbsolutePaths():
|
if not noAbsolutePaths(conf):
|
||||||
if not exefile.isAbsolute():
|
if not exefile.isAbsolute():
|
||||||
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
||||||
when false:
|
when false:
|
||||||
if optCDebug in gGlobalOptions:
|
if optCDebug in gGlobalOptions:
|
||||||
writeDebugInfo(exefile.changeFileExt("ndb"))
|
writeDebugInfo(exefile.changeFileExt("ndb"))
|
||||||
exefile = quoteShell(exefile)
|
exefile = quoteShell(exefile)
|
||||||
let linkOptions = getLinkOptions() & " " &
|
let linkOptions = getLinkOptions(conf) & " " &
|
||||||
getConfigVar(cCompiler, ".options.linker")
|
getConfigVar(conf, cCompiler, ".options.linker")
|
||||||
var linkTmpl = getConfigVar(cCompiler, ".linkTmpl")
|
var linkTmpl = getConfigVar(conf, cCompiler, ".linkTmpl")
|
||||||
if linkTmpl.len == 0:
|
if linkTmpl.len == 0:
|
||||||
linkTmpl = CC[cCompiler].linkTmpl
|
linkTmpl = CC[cCompiler].linkTmpl
|
||||||
result = quoteShell(result % ["builddll", builddll,
|
result = quoteShell(result % ["builddll", builddll,
|
||||||
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
||||||
"exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
|
"exefile", exefile, "nim", getPrefixDir(conf), "lib", libpath])
|
||||||
result.add ' '
|
result.add ' '
|
||||||
addf(result, linkTmpl, ["builddll", builddll,
|
addf(result, linkTmpl, ["builddll", builddll,
|
||||||
"buildgui", buildgui, "options", linkOptions,
|
"buildgui", buildgui, "options", linkOptions,
|
||||||
"objfiles", objfiles, "exefile", exefile,
|
"objfiles", objfiles, "exefile", exefile,
|
||||||
"nim", quoteShell(getPrefixDir()),
|
"nim", quoteShell(getPrefixDir(conf)),
|
||||||
"lib", quoteShell(libpath)])
|
"lib", quoteShell(libpath)])
|
||||||
|
|
||||||
template tryExceptOSErrorMessage(errorPrefix: string = "", body: untyped): typed =
|
template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped): typed =
|
||||||
try:
|
try:
|
||||||
body
|
body
|
||||||
except OSError:
|
except OSError:
|
||||||
let ose = (ref OSError)(getCurrentException())
|
let ose = (ref OSError)(getCurrentException())
|
||||||
if errorPrefix.len > 0:
|
if errorPrefix.len > 0:
|
||||||
rawMessage(errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode)
|
rawMessage(conf, errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode)
|
||||||
else:
|
else:
|
||||||
rawMessage(errExecutionOfProgramFailed, ose.msg & " " & $ose.errorCode)
|
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
|
||||||
|
(ose.msg & " " & $ose.errorCode))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
proc execLinkCmd(linkCmd: string) =
|
proc execLinkCmd(conf: ConfigRef; linkCmd: string) =
|
||||||
tryExceptOSErrorMessage("invocation of external linker program failed."):
|
tryExceptOSErrorMessage(conf, "invocation of external linker program failed."):
|
||||||
execExternalProgram(linkCmd,
|
execExternalProgram(conf, linkCmd,
|
||||||
if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
|
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 runCb = proc (idx: int, p: Process) =
|
||||||
let exitCode = p.peekExitCode
|
let exitCode = p.peekExitCode
|
||||||
if exitCode != 0:
|
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" &
|
cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" &
|
||||||
p.outputStream.readAll.strip)
|
p.outputStream.readAll.strip)
|
||||||
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
||||||
var res = 0
|
var res = 0
|
||||||
if gNumberOfProcessors <= 1:
|
if gNumberOfProcessors <= 1:
|
||||||
for i in countup(0, high(cmds)):
|
for i in countup(0, high(cmds)):
|
||||||
tryExceptOSErrorMessage("invocation of external compiler program failed."):
|
tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."):
|
||||||
res = execWithEcho(cmds[i])
|
res = execWithEcho(conf, cmds[i])
|
||||||
if res != 0: rawMessage(errExecutionOfProgramFailed, cmds[i])
|
if res != 0:
|
||||||
|
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
|
||||||
|
cmds[i])
|
||||||
else:
|
else:
|
||||||
tryExceptOSErrorMessage("invocation of external compiler program failed."):
|
tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."):
|
||||||
if optListCmd in gGlobalOptions or gVerbosity > 1:
|
if optListCmd in gGlobalOptions or gVerbosity > 1:
|
||||||
res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath},
|
res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath},
|
||||||
gNumberOfProcessors, afterRunEvent=runCb)
|
gNumberOfProcessors, afterRunEvent=runCb)
|
||||||
|
|
@ -744,9 +751,10 @@ proc execCmdsInParallel(cmds: seq[string]; prettyCb: proc (idx: int)) =
|
||||||
gNumberOfProcessors, afterRunEvent=runCb)
|
gNumberOfProcessors, afterRunEvent=runCb)
|
||||||
if res != 0:
|
if res != 0:
|
||||||
if gNumberOfProcessors <= 1:
|
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
|
var
|
||||||
linkCmd: string
|
linkCmd: string
|
||||||
if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
|
if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
|
||||||
|
|
@ -758,36 +766,36 @@ proc callCCompiler*(projectfile: string) =
|
||||||
var prettyCmds: TStringSeq = @[]
|
var prettyCmds: TStringSeq = @[]
|
||||||
let prettyCb = proc (idx: int) =
|
let prettyCb = proc (idx: int) =
|
||||||
echo prettyCmds[idx]
|
echo prettyCmds[idx]
|
||||||
compileCFile(toCompile, script, cmds, prettyCmds)
|
compileCFile(conf, toCompile, script, cmds, prettyCmds)
|
||||||
if optCompileOnly notin gGlobalOptions:
|
if optCompileOnly notin gGlobalOptions:
|
||||||
execCmdsInParallel(cmds, prettyCb)
|
execCmdsInParallel(conf, cmds, prettyCb)
|
||||||
if optNoLinking notin gGlobalOptions:
|
if optNoLinking notin gGlobalOptions:
|
||||||
# call the linker:
|
# call the linker:
|
||||||
var objfiles = ""
|
var objfiles = ""
|
||||||
for it in externalToLink:
|
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, ' ')
|
||||||
add(objfiles, quoteShell(
|
add(objfiles, quoteShell(
|
||||||
addFileExt(objFile, CC[cCompiler].objExt)))
|
addFileExt(objFile, CC[cCompiler].objExt)))
|
||||||
for x in toCompile:
|
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, ' ')
|
||||||
add(objfiles, quoteShell(objFile))
|
add(objfiles, quoteShell(objFile))
|
||||||
|
|
||||||
linkCmd = getLinkCmd(projectfile, objfiles)
|
linkCmd = getLinkCmd(conf, projectfile, objfiles)
|
||||||
if optCompileOnly notin gGlobalOptions:
|
if optCompileOnly notin gGlobalOptions:
|
||||||
execLinkCmd(linkCmd)
|
execLinkCmd(conf, linkCmd)
|
||||||
else:
|
else:
|
||||||
linkCmd = ""
|
linkCmd = ""
|
||||||
if optGenScript in gGlobalOptions:
|
if optGenScript in gGlobalOptions:
|
||||||
add(script, linkCmd)
|
add(script, linkCmd)
|
||||||
add(script, tnl)
|
add(script, tnl)
|
||||||
generateScript(projectfile, script)
|
generateScript(conf, projectfile, script)
|
||||||
|
|
||||||
#from json import escapeJson
|
#from json import escapeJson
|
||||||
import json
|
import json
|
||||||
|
|
||||||
proc writeJsonBuildInstructions*(projectfile: string) =
|
proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||||
template lit(x: untyped) = f.write x
|
template lit(x: untyped) = f.write x
|
||||||
template str(x: untyped) =
|
template str(x: untyped) =
|
||||||
when compiles(escapeJson(x, buf)):
|
when compiles(escapeJson(x, buf)):
|
||||||
|
|
@ -797,11 +805,11 @@ proc writeJsonBuildInstructions*(projectfile: string) =
|
||||||
else:
|
else:
|
||||||
f.write escapeJson(x)
|
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
|
var pastStart = false
|
||||||
for it in clist:
|
for it in clist:
|
||||||
if CfileFlag.Cached in it.flags: continue
|
if CfileFlag.Cached in it.flags: continue
|
||||||
let compileCmd = getCompileCFileCmd(it)
|
let compileCmd = getCompileCFileCmd(conf, it)
|
||||||
if pastStart: lit "],\L"
|
if pastStart: lit "],\L"
|
||||||
lit "["
|
lit "["
|
||||||
str it.cname
|
str it.cname
|
||||||
|
|
@ -810,11 +818,11 @@ proc writeJsonBuildInstructions*(projectfile: string) =
|
||||||
pastStart = true
|
pastStart = true
|
||||||
lit "]\L"
|
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]) =
|
llist: seq[string]) =
|
||||||
var pastStart = false
|
var pastStart = false
|
||||||
for it in llist:
|
for it in llist:
|
||||||
let objfile = if noAbsolutePaths(): it.extractFilename
|
let objfile = if noAbsolutePaths(conf): it.extractFilename
|
||||||
else: it
|
else: it
|
||||||
let objstr = addFileExt(objfile, CC[cCompiler].objExt)
|
let objstr = addFileExt(objfile, CC[cCompiler].objExt)
|
||||||
add(objfiles, ' ')
|
add(objfiles, ' ')
|
||||||
|
|
@ -835,25 +843,25 @@ proc writeJsonBuildInstructions*(projectfile: string) =
|
||||||
var buf = newStringOfCap(50)
|
var buf = newStringOfCap(50)
|
||||||
|
|
||||||
let file = projectfile.splitFile.name
|
let file = projectfile.splitFile.name
|
||||||
let jsonFile = toGeneratedFile(file, "json")
|
let jsonFile = toGeneratedFile(conf, file, "json")
|
||||||
|
|
||||||
var f: File
|
var f: File
|
||||||
if open(f, jsonFile, fmWrite):
|
if open(f, jsonFile, fmWrite):
|
||||||
lit "{\"compile\":[\L"
|
lit "{\"compile\":[\L"
|
||||||
cfiles(f, buf, toCompile, false)
|
cfiles(conf, f, buf, toCompile, false)
|
||||||
lit "],\L\"link\":[\L"
|
lit "],\L\"link\":[\L"
|
||||||
var objfiles = ""
|
var objfiles = ""
|
||||||
# XXX add every file here that is to link
|
# 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\": "
|
lit "],\L\"linkcmd\": "
|
||||||
str getLinkCmd(projectfile, objfiles)
|
str getLinkCmd(conf, projectfile, objfiles)
|
||||||
lit "\L}\L"
|
lit "\L}\L"
|
||||||
close(f)
|
close(f)
|
||||||
|
|
||||||
proc runJsonBuildInstructions*(projectfile: string) =
|
proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||||
let file = projectfile.splitFile.name
|
let file = projectfile.splitFile.name
|
||||||
let jsonFile = toGeneratedFile(file, "json")
|
let jsonFile = toGeneratedFile(conf, file, "json")
|
||||||
try:
|
try:
|
||||||
let data = json.parseFile(jsonFile)
|
let data = json.parseFile(jsonFile)
|
||||||
let toCompile = data["compile"]
|
let toCompile = data["compile"]
|
||||||
|
|
@ -870,32 +878,32 @@ proc runJsonBuildInstructions*(projectfile: string) =
|
||||||
|
|
||||||
let prettyCb = proc (idx: int) =
|
let prettyCb = proc (idx: int) =
|
||||||
echo prettyCmds[idx]
|
echo prettyCmds[idx]
|
||||||
execCmdsInParallel(cmds, prettyCb)
|
execCmdsInParallel(conf, cmds, prettyCb)
|
||||||
|
|
||||||
let linkCmd = data["linkcmd"]
|
let linkCmd = data["linkcmd"]
|
||||||
doAssert linkCmd.kind == JString
|
doAssert linkCmd.kind == JString
|
||||||
execLinkCmd(linkCmd.getStr)
|
execLinkCmd(conf, linkCmd.getStr)
|
||||||
except:
|
except:
|
||||||
echo getCurrentException().getStackTrace()
|
echo getCurrentException().getStackTrace()
|
||||||
quit "error evaluating JSON file: " & jsonFile
|
quit "error evaluating JSON file: " & jsonFile
|
||||||
|
|
||||||
proc genMappingFiles(list: CFileList): Rope =
|
proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope =
|
||||||
for it in list:
|
for it in list:
|
||||||
addf(result, "--file:r\"$1\"$N", [rope(it.cname)])
|
addf(result, "--file:r\"$1\"$N", [rope(it.cname)])
|
||||||
|
|
||||||
proc writeMapping*(gSymbolMapping: Rope) =
|
proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) =
|
||||||
if optGenMapping notin gGlobalOptions: return
|
if optGenMapping notin gGlobalOptions: return
|
||||||
var code = rope("[C_Files]\n")
|
var code = rope("[C_Files]\n")
|
||||||
add(code, genMappingFiles(toCompile))
|
add(code, genMappingFiles(conf, toCompile))
|
||||||
add(code, "\n[C_Compiler]\nFlags=")
|
add(code, "\n[C_Compiler]\nFlags=")
|
||||||
add(code, strutils.escape(getCompileOptions()))
|
add(code, strutils.escape(getCompileOptions(conf)))
|
||||||
|
|
||||||
add(code, "\n[Linker]\nFlags=")
|
add(code, "\n[Linker]\nFlags=")
|
||||||
add(code, strutils.escape(getLinkOptions() & " " &
|
add(code, strutils.escape(getLinkOptions(conf) & " " &
|
||||||
getConfigVar(cCompiler, ".options.linker")))
|
getConfigVar(conf, cCompiler, ".options.linker")))
|
||||||
|
|
||||||
add(code, "\n[Environment]\nlibpath=")
|
add(code, "\n[Environment]\nlibpath=")
|
||||||
add(code, strutils.escape(libpath))
|
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"))
|
writeRope(code, joinPath(gProjectPath, "mapping.txt"))
|
||||||
|
|
|
||||||
|
|
@ -36,20 +36,20 @@ proc setId*(id: int) {.inline.} =
|
||||||
proc idSynchronizationPoint*(idRange: int) =
|
proc idSynchronizationPoint*(idRange: int) =
|
||||||
gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1
|
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
|
# 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
|
# will cause strange bugs if multiple projects are in the same folder, so
|
||||||
# we simply use a project independent name:
|
# we simply use a project independent name:
|
||||||
result = options.completeGeneratedFilePath("nim.gid")
|
result = options.completeGeneratedFilePath(conf, "nim.gid")
|
||||||
|
|
||||||
proc saveMaxIds*(project: string) =
|
proc saveMaxIds*(conf: ConfigRef; project: string) =
|
||||||
var f = open(project.toGid, fmWrite)
|
var f = open(toGid(conf, project), fmWrite)
|
||||||
f.writeLine($gFrontEndId)
|
f.writeLine($gFrontEndId)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
proc loadMaxIds*(project: string) =
|
proc loadMaxIds*(conf: ConfigRef; project: string) =
|
||||||
var f: File
|
var f: File
|
||||||
if open(f, project.toGid, fmRead):
|
if open(f, toGid(conf, project), fmRead):
|
||||||
var line = newStringOfCap(20)
|
var line = newStringOfCap(20)
|
||||||
if f.readLine(line):
|
if f.readLine(line):
|
||||||
var frontEndId = parseInt(line)
|
var frontEndId = parseInt(line)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
|
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
|
||||||
wordrecg
|
wordrecg, configuration
|
||||||
|
|
||||||
const
|
const
|
||||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||||
|
|
@ -131,7 +131,7 @@ type
|
||||||
# like 0b01 or r"\L" are unaffected
|
# like 0b01 or r"\L" are unaffected
|
||||||
commentOffsetA*, commentOffsetB*: int
|
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
|
TLexer* = object of TBaseLexer
|
||||||
fileIdx*: FileIndex
|
fileIdx*: FileIndex
|
||||||
indentAhead*: int # if > 0 an indendation has already been read
|
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;
|
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream;
|
||||||
cache: IdentCache; config: ConfigRef) =
|
cache: IdentCache; config: ConfigRef) =
|
||||||
openLexer(lex, filename.fileInfoIdx, inputstream, cache, config)
|
openLexer(lex, fileInfoIdx(config, filename), inputstream, cache, config)
|
||||||
|
|
||||||
proc closeLexer*(lex: var TLexer) =
|
proc closeLexer*(lex: var TLexer) =
|
||||||
if lex.config != nil:
|
if lex.config != nil:
|
||||||
|
|
@ -246,9 +246,9 @@ proc getLineInfo(L: TLexer): TLineInfo =
|
||||||
|
|
||||||
proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
|
proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
|
||||||
if L.errorHandler.isNil:
|
if L.errorHandler.isNil:
|
||||||
msgs.message(info, msg, arg)
|
msgs.message(L.config, info, msg, arg)
|
||||||
else:
|
else:
|
||||||
L.errorHandler(info, msg, arg)
|
L.errorHandler(L.config, info, msg, arg)
|
||||||
|
|
||||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
||||||
L.dispMessage(getLineInfo(L), msg, arg)
|
L.dispMessage(getLineInfo(L), msg, arg)
|
||||||
|
|
@ -341,7 +341,8 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
break
|
break
|
||||||
if buf[pos] == '_':
|
if buf[pos] == '_':
|
||||||
if buf[pos+1] notin chars:
|
if buf[pos+1] notin chars:
|
||||||
lexMessage(L, errInvalidToken, "_")
|
lexMessage(L, errGenerated,
|
||||||
|
"only single underscores may occur in a token: '__' is invalid")
|
||||||
break
|
break
|
||||||
add(tok.literal, '_')
|
add(tok.literal, '_')
|
||||||
inc(pos)
|
inc(pos)
|
||||||
|
|
@ -355,7 +356,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
inc(pos)
|
inc(pos)
|
||||||
L.bufpos = 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.
|
# Used to get slightly human friendlier err messages.
|
||||||
# Note: the erroneous 'O' char in the character set is intentional
|
# Note: the erroneous 'O' char in the character set is intentional
|
||||||
const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O',
|
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])
|
add(t.literal, L.buf[L.bufpos])
|
||||||
matchChars(L, t, {'0'..'9'})
|
matchChars(L, t, {'0'..'9'})
|
||||||
L.bufpos = msgPos
|
L.bufpos = msgPos
|
||||||
lexMessage(L, msg, t.literal)
|
lexMessage(L, errGenerated, msg % t.literal)
|
||||||
|
|
||||||
var
|
var
|
||||||
startpos, endpos: int
|
startpos, endpos: int
|
||||||
|
|
@ -398,7 +399,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
eatChar(L, result, '0')
|
eatChar(L, result, '0')
|
||||||
case L.buf[L.bufpos]
|
case L.buf[L.bufpos]
|
||||||
of 'O':
|
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':
|
of 'x', 'X':
|
||||||
eatChar(L, result, 'x')
|
eatChar(L, result, 'x')
|
||||||
matchUnderscoreChars(L, result, {'0'..'9', 'a'..'f', 'A'..'F'})
|
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')
|
eatChar(L, result, 'b')
|
||||||
matchUnderscoreChars(L, result, {'0'..'1'})
|
matchUnderscoreChars(L, result, {'0'..'1'})
|
||||||
else:
|
else:
|
||||||
internalError(getLineInfo(L), "getNumber")
|
internalError(L.config, getLineInfo(L), "getNumber")
|
||||||
else:
|
else:
|
||||||
matchUnderscoreChars(L, result, {'0'..'9'})
|
matchUnderscoreChars(L, result, {'0'..'9'})
|
||||||
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'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
|
result.tokType = tkInt8Lit
|
||||||
inc(postPos)
|
inc(postPos)
|
||||||
else:
|
else:
|
||||||
lexMessageLitNum(L, errInvalidNumber, startpos)
|
lexMessageLitNum(L, "invalid number: '$1'", startpos)
|
||||||
of 'u', 'U':
|
of 'u', 'U':
|
||||||
inc(postPos)
|
inc(postPos)
|
||||||
if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
|
if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
|
||||||
|
|
@ -482,12 +483,12 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
else:
|
else:
|
||||||
result.tokType = tkUIntLit
|
result.tokType = tkUIntLit
|
||||||
else:
|
else:
|
||||||
lexMessageLitNum(L, errInvalidNumber, startpos)
|
lexMessageLitNum(L, "invalid number: '$1'", startpos)
|
||||||
|
|
||||||
# Is there still a literalish char awaiting? Then it's an error!
|
# Is there still a literalish char awaiting? Then it's an error!
|
||||||
if L.buf[postPos] in literalishChars or
|
if L.buf[postPos] in literalishChars or
|
||||||
(L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}):
|
(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
|
# Third stage, extract actual number
|
||||||
L.bufpos = startpos # restore position
|
L.bufpos = startpos # restore position
|
||||||
|
|
@ -528,7 +529,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
internalError(getLineInfo(L), "getNumber")
|
internalError(L.config, getLineInfo(L), "getNumber")
|
||||||
|
|
||||||
case result.tokType
|
case result.tokType
|
||||||
of tkIntLit, tkInt64Lit: result.iNumber = xi
|
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!
|
# XXX: Test this on big endian machine!
|
||||||
of tkFloat64Lit, tkFloatLit:
|
of tkFloat64Lit, tkFloatLit:
|
||||||
result.fNumber = (cast[PFloat64](addr(xi)))[]
|
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
|
# Bounds checks. Non decimal literals are allowed to overflow the range of
|
||||||
# the datatype as long as their pattern don't overflow _bitwise_, hence
|
# 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:
|
if outOfRange:
|
||||||
#echo "out of range num: ", result.iNumber, " vs ", xi
|
#echo "out of range num: ", result.iNumber, " vs ", xi
|
||||||
lexMessageLitNum(L, errNumberOutOfRange, startpos)
|
lexMessageLitNum(L, "number out of range: '$1'", startpos)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
case result.tokType
|
case result.tokType
|
||||||
|
|
@ -590,7 +591,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
result.iNumber > BiggestInt(uint32.high))
|
result.iNumber > BiggestInt(uint32.high))
|
||||||
else: false
|
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
|
# Promote int literal to int64? Not always necessary, but more consistent
|
||||||
if result.tokType == tkIntLit:
|
if result.tokType == tkIntLit:
|
||||||
|
|
@ -598,9 +599,9 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
result.tokType = tkInt64Lit
|
result.tokType = tkInt64Lit
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
lexMessageLitNum(L, errInvalidNumber, startpos)
|
lexMessageLitNum(L, "invalid number: '$1'", startpos)
|
||||||
except OverflowError, RangeError:
|
except OverflowError, RangeError:
|
||||||
lexMessageLitNum(L, errNumberOutOfRange, startpos)
|
lexMessageLitNum(L, "number out of range: '$1'", startpos)
|
||||||
tokenEnd(result, postPos-1)
|
tokenEnd(result, postPos-1)
|
||||||
L.bufpos = postPos
|
L.bufpos = postPos
|
||||||
|
|
||||||
|
|
@ -627,7 +628,8 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
|
||||||
case L.buf[L.bufpos]
|
case L.buf[L.bufpos]
|
||||||
of 'n', 'N':
|
of 'n', 'N':
|
||||||
if gOldNewlines:
|
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)
|
add(tok.literal, tnl)
|
||||||
else:
|
else:
|
||||||
add(tok.literal, '\L')
|
add(tok.literal, '\L')
|
||||||
|
|
@ -696,8 +698,8 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
|
||||||
var xi = 0
|
var xi = 0
|
||||||
handleDecChars(L, xi)
|
handleDecChars(L, xi)
|
||||||
if (xi <= 255): add(tok.literal, chr(xi))
|
if (xi <= 255): add(tok.literal, chr(xi))
|
||||||
else: lexMessage(L, errInvalidCharacterConstant)
|
else: lexMessage(L, errGenerated, "invalid character constant")
|
||||||
else: lexMessage(L, errInvalidCharacterConstant)
|
else: lexMessage(L, errGenerated, "invalid character constant")
|
||||||
|
|
||||||
proc newString(s: cstring, len: int): string =
|
proc newString(s: cstring, len: int): string =
|
||||||
## XXX, how come there is no support for this?
|
## 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)
|
tokenEndIgnore(tok, pos)
|
||||||
var line2 = L.lineNumber
|
var line2 = L.lineNumber
|
||||||
L.lineNumber = line
|
L.lineNumber = line
|
||||||
lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
|
lexMessagePos(L, errGenerated, L.lineStart, "closing \"\"\" expected, but end of file reached")
|
||||||
L.lineNumber = line2
|
L.lineNumber = line2
|
||||||
L.bufpos = pos
|
L.bufpos = pos
|
||||||
break
|
break
|
||||||
|
|
@ -784,7 +786,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
|
||||||
break
|
break
|
||||||
elif c in {CR, LF, nimlexbase.EndOfFile}:
|
elif c in {CR, LF, nimlexbase.EndOfFile}:
|
||||||
tokenEndIgnore(tok, pos)
|
tokenEndIgnore(tok, pos)
|
||||||
lexMessage(L, errClosingQuoteExpected)
|
lexMessage(L, errGenerated, "closing \" expected")
|
||||||
break
|
break
|
||||||
elif (c == '\\') and not rawMode:
|
elif (c == '\\') and not rawMode:
|
||||||
L.bufpos = pos
|
L.bufpos = pos
|
||||||
|
|
@ -800,12 +802,13 @@ proc getCharacter(L: var TLexer, tok: var TToken) =
|
||||||
inc(L.bufpos) # skip '
|
inc(L.bufpos) # skip '
|
||||||
var c = L.buf[L.bufpos]
|
var c = L.buf[L.bufpos]
|
||||||
case c
|
case c
|
||||||
of '\0'..pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
|
of '\0'..pred(' '), '\'': lexMessage(L, errGenerated, "invalid character literal")
|
||||||
of '\\': getEscapedChar(L, tok)
|
of '\\': getEscapedChar(L, tok)
|
||||||
else:
|
else:
|
||||||
tok.literal = $c
|
tok.literal = $c
|
||||||
inc(L.bufpos)
|
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)
|
tokenEndIgnore(tok, L.bufpos)
|
||||||
inc(L.bufpos) # skip '
|
inc(L.bufpos) # skip '
|
||||||
|
|
||||||
|
|
@ -826,7 +829,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
|
||||||
inc(pos)
|
inc(pos)
|
||||||
of '_':
|
of '_':
|
||||||
if buf[pos+1] notin SymChars:
|
if buf[pos+1] notin SymChars:
|
||||||
lexMessage(L, errInvalidToken, "_")
|
lexMessage(L, errGenerated, "invalid token: trailing underscore")
|
||||||
break
|
break
|
||||||
inc(pos)
|
inc(pos)
|
||||||
else: break
|
else: break
|
||||||
|
|
@ -1014,7 +1017,7 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||||
inc(pos)
|
inc(pos)
|
||||||
inc(tok.strongSpaceA)
|
inc(tok.strongSpaceA)
|
||||||
of '\t':
|
of '\t':
|
||||||
if not L.allowTabs: lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
|
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabulators are not allowed")
|
||||||
inc(pos)
|
inc(pos)
|
||||||
of CR, LF:
|
of CR, LF:
|
||||||
tokenEndPrevious(tok, pos)
|
tokenEndPrevious(tok, pos)
|
||||||
|
|
@ -1182,7 +1185,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||||
else:
|
else:
|
||||||
tok.literal = $c
|
tok.literal = $c
|
||||||
tok.tokType = tkInvalid
|
tok.tokType = tkInvalid
|
||||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')')
|
||||||
of '\"':
|
of '\"':
|
||||||
# check for extended raw string literal:
|
# check for extended raw string literal:
|
||||||
var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
|
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)
|
getNumber(L, tok)
|
||||||
let c = L.buf[L.bufpos]
|
let c = L.buf[L.bufpos]
|
||||||
if c in SymChars+{'_'}:
|
if c in SymChars+{'_'}:
|
||||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier")
|
||||||
else:
|
else:
|
||||||
if c in OpChars:
|
if c in OpChars:
|
||||||
getOperator(L, tok)
|
getOperator(L, tok)
|
||||||
|
|
@ -1209,6 +1212,6 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||||
else:
|
else:
|
||||||
tok.literal = $c
|
tok.literal = $c
|
||||||
tok.tokType = tkInvalid
|
tok.tokType = tkInvalid
|
||||||
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
|
lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')')
|
||||||
inc(L.bufpos)
|
inc(L.bufpos)
|
||||||
atTokenEnd()
|
atTokenEnd()
|
||||||
|
|
|
||||||
|
|
@ -8,481 +8,13 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import
|
import
|
||||||
options, strutils, os, tables, ropes, platform, terminal, macros
|
options, strutils, os, tables, ropes, platform, terminal, macros,
|
||||||
|
configuration
|
||||||
|
|
||||||
const
|
#type
|
||||||
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
|
# MsgConfig* = ref object of RootObj
|
||||||
|
|
||||||
type
|
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
|
TFileInfo* = object
|
||||||
fullPath: string # This is a canonical full filesystem path
|
fullPath: string # This is a canonical full filesystem path
|
||||||
projPath*: string # This is relative to the project's root
|
projPath*: string # This is relative to the project's root
|
||||||
|
|
@ -527,35 +59,11 @@ type
|
||||||
|
|
||||||
proc `==`*(a, b: FileIndex): bool {.borrow.}
|
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
|
const
|
||||||
InvalidFileIDX* = FileIndex(-1)
|
InvalidFileIDX* = FileIndex(-1)
|
||||||
|
|
||||||
var
|
var
|
||||||
ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
|
|
||||||
hintQuitCalled, hintExecuting}
|
|
||||||
filenameToIndexTbl = initTable[string, FileIndex]()
|
filenameToIndexTbl = initTable[string, FileIndex]()
|
||||||
fileInfos*: seq[TFileInfo] = @[]
|
fileInfos*: seq[TFileInfo] = @[]
|
||||||
systemFileIdx*: FileIndex
|
systemFileIdx*: FileIndex
|
||||||
|
|
@ -606,22 +114,22 @@ when defined(nimpretty):
|
||||||
proc fileSection*(fid: FileIndex; a, b: int): string =
|
proc fileSection*(fid: FileIndex; a, b: int): string =
|
||||||
substr(fileInfos[fid.int].fullContent, a, b)
|
substr(fileInfos[fid.int].fullContent, a, b)
|
||||||
|
|
||||||
proc fileInfoKnown*(filename: string): bool =
|
proc fileInfoKnown*(conf: ConfigRef; filename: string): bool =
|
||||||
var
|
var
|
||||||
canon: string
|
canon: string
|
||||||
try:
|
try:
|
||||||
canon = canonicalizePath(filename)
|
canon = canonicalizePath(conf, filename)
|
||||||
except:
|
except:
|
||||||
canon = filename
|
canon = filename
|
||||||
result = filenameToIndexTbl.hasKey(canon)
|
result = filenameToIndexTbl.hasKey(canon)
|
||||||
|
|
||||||
proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
|
proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex =
|
||||||
var
|
var
|
||||||
canon: string
|
canon: string
|
||||||
pseudoPath = false
|
pseudoPath = false
|
||||||
|
|
||||||
try:
|
try:
|
||||||
canon = canonicalizePath(filename)
|
canon = canonicalizePath(conf, filename)
|
||||||
shallow(canon)
|
shallow(canon)
|
||||||
except:
|
except:
|
||||||
canon = filename
|
canon = filename
|
||||||
|
|
@ -635,21 +143,22 @@ proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
|
||||||
isKnownFile = false
|
isKnownFile = false
|
||||||
result = fileInfos.len.FileIndex
|
result = fileInfos.len.FileIndex
|
||||||
fileInfos.add(newFileInfo(canon, if pseudoPath: filename
|
fileInfos.add(newFileInfo(canon, if pseudoPath: filename
|
||||||
else: canon.shortenDir))
|
else: shortenDir(conf, canon)))
|
||||||
filenameToIndexTbl[canon] = result
|
filenameToIndexTbl[canon] = result
|
||||||
|
|
||||||
proc fileInfoIdx*(filename: string): FileIndex =
|
proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex =
|
||||||
var dummy: bool
|
var dummy: bool
|
||||||
result = fileInfoIdx(filename, dummy)
|
result = fileInfoIdx(conf, filename, dummy)
|
||||||
|
|
||||||
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||||
result.fileIndex = fileInfoIdx
|
result.fileIndex = fileInfoIdx
|
||||||
result.line = uint16(line)
|
result.line = uint16(line)
|
||||||
result.col = int16(col)
|
result.col = int16(col)
|
||||||
|
|
||||||
proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
|
proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} =
|
||||||
result = newLineInfo(filename.fileInfoIdx, line, col)
|
result = newLineInfo(fileInfoIdx(conf, filename), line, col)
|
||||||
|
|
||||||
|
when false:
|
||||||
fileInfos.add(newFileInfo("", "command line"))
|
fileInfos.add(newFileInfo("", "command line"))
|
||||||
var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
|
var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
|
||||||
|
|
||||||
|
|
@ -661,14 +170,6 @@ proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
||||||
|
|
||||||
proc sourceLine*(i: TLineInfo): Rope
|
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 =
|
proc unknownLineInfo*(): TLineInfo =
|
||||||
result.line = uint16(0)
|
result.line = uint16(0)
|
||||||
result.col = int16(-1)
|
result.col = int16(-1)
|
||||||
|
|
@ -892,8 +393,8 @@ proc log*(s: string) {.procvar.} =
|
||||||
f.writeLine(s)
|
f.writeLine(s)
|
||||||
close(f)
|
close(f)
|
||||||
|
|
||||||
proc quit(msg: TMsgKind) =
|
proc quit(conf: ConfigRef; msg: TMsgKind) =
|
||||||
if defined(debug) or msg == errInternal or hintStackTrace in gNotes:
|
if defined(debug) or msg == errInternal or hintStackTrace in conf.notes:
|
||||||
if stackTraceAvailable() and isNil(writelnHook):
|
if stackTraceAvailable() and isNil(writelnHook):
|
||||||
writeStackTrace()
|
writeStackTrace()
|
||||||
else:
|
else:
|
||||||
|
|
@ -902,17 +403,17 @@ proc quit(msg: TMsgKind) =
|
||||||
options.command & " <file>")
|
options.command & " <file>")
|
||||||
quit 1
|
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 msg >= fatalMin and msg <= fatalMax:
|
||||||
if gCmd == cmdIdeTools: log(s)
|
if gCmd == cmdIdeTools: log(s)
|
||||||
quit(msg)
|
quit(conf, msg)
|
||||||
if msg >= errMin and msg <= errMax:
|
if msg >= errMin and msg <= errMax:
|
||||||
inc(gErrorCounter)
|
inc(conf.errorCounter)
|
||||||
options.gExitcode = 1'i8
|
options.gExitcode = 1'i8
|
||||||
if gErrorCounter >= gErrorMax:
|
if conf.errorCounter >= conf.errorMax:
|
||||||
quit(msg)
|
quit(conf, msg)
|
||||||
elif eh == doAbort and gCmd != cmdIdeTools:
|
elif eh == doAbort and gCmd != cmdIdeTools:
|
||||||
quit(msg)
|
quit(conf, msg)
|
||||||
elif eh == doRaise:
|
elif eh == doRaise:
|
||||||
raiseRecoverableError(s)
|
raiseRecoverableError(s)
|
||||||
|
|
||||||
|
|
@ -922,12 +423,13 @@ proc `==`*(a, b: TLineInfo): bool =
|
||||||
proc exactEquals*(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
|
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
|
var info = lastinfo
|
||||||
for i in countup(0, len(msgContext) - 1):
|
for i in countup(0, len(msgContext) - 1):
|
||||||
if msgContext[i] != lastinfo and msgContext[i] != info:
|
if msgContext[i] != lastinfo and msgContext[i] != info:
|
||||||
if structuredErrorHook != nil:
|
if structuredErrorHook != nil:
|
||||||
structuredErrorHook(msgContext[i], getMessageStr(errInstantiationFrom, ""),
|
structuredErrorHook(msgContext[i], instantiationFrom,
|
||||||
Severity.Error)
|
Severity.Error)
|
||||||
else:
|
else:
|
||||||
styledMsgWriteln(styleBright,
|
styledMsgWriteln(styleBright,
|
||||||
|
|
@ -935,13 +437,13 @@ proc writeContext(lastinfo: TLineInfo) =
|
||||||
coordToStr(msgContext[i].line.int),
|
coordToStr(msgContext[i].line.int),
|
||||||
coordToStr(msgContext[i].col+1)],
|
coordToStr(msgContext[i].col+1)],
|
||||||
resetStyle,
|
resetStyle,
|
||||||
getMessageStr(errInstantiationFrom, ""))
|
instantiationFrom)
|
||||||
info = msgContext[i]
|
info = msgContext[i]
|
||||||
|
|
||||||
proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
|
proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool =
|
||||||
msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
|
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
|
var
|
||||||
title: string
|
title: string
|
||||||
color: ForegroundColor
|
color: ForegroundColor
|
||||||
|
|
@ -950,43 +452,43 @@ proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
|
||||||
case msg
|
case msg
|
||||||
of errMin..errMax:
|
of errMin..errMax:
|
||||||
sev = Severity.Error
|
sev = Severity.Error
|
||||||
writeContext(unknownLineInfo())
|
writeContext(conf, unknownLineInfo())
|
||||||
title = ErrorTitle
|
title = ErrorTitle
|
||||||
color = ErrorColor
|
color = ErrorColor
|
||||||
of warnMin..warnMax:
|
of warnMin..warnMax:
|
||||||
sev = Severity.Warning
|
sev = Severity.Warning
|
||||||
if optWarns notin gOptions: return
|
if optWarns notin gOptions: return
|
||||||
if msg notin gNotes: return
|
if msg notin conf.notes: return
|
||||||
writeContext(unknownLineInfo())
|
writeContext(conf, unknownLineInfo())
|
||||||
title = WarningTitle
|
title = WarningTitle
|
||||||
color = WarningColor
|
color = WarningColor
|
||||||
kind = WarningsToStr[ord(msg) - ord(warnMin)]
|
kind = WarningsToStr[ord(msg) - ord(warnMin)]
|
||||||
inc(gWarnCounter)
|
inc(conf.warnCounter)
|
||||||
of hintMin..hintMax:
|
of hintMin..hintMax:
|
||||||
sev = Severity.Hint
|
sev = Severity.Hint
|
||||||
if optHints notin gOptions: return
|
if optHints notin gOptions: return
|
||||||
if msg notin gNotes: return
|
if msg notin conf.notes: return
|
||||||
title = HintTitle
|
title = HintTitle
|
||||||
color = HintColor
|
color = HintColor
|
||||||
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
|
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||||
inc(gHintCounter)
|
inc(conf.hintCounter)
|
||||||
let s = msgKindToString(msg) % args
|
let s = msgKindToString(msg) % args
|
||||||
|
|
||||||
if structuredErrorHook != nil:
|
if structuredErrorHook != nil:
|
||||||
structuredErrorHook(unknownLineInfo(), s & (if kind != nil: KindFormat % kind else: ""), sev)
|
structuredErrorHook(unknownLineInfo(), s & (if kind != nil: KindFormat % kind else: ""), sev)
|
||||||
|
|
||||||
if not ignoreMsgBecauseOfIdeTools(msg):
|
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
||||||
if kind != nil:
|
if kind != nil:
|
||||||
styledMsgWriteln(color, title, resetStyle, s,
|
styledMsgWriteln(color, title, resetStyle, s,
|
||||||
KindColor, `%`(KindFormat, kind))
|
KindColor, `%`(KindFormat, kind))
|
||||||
else:
|
else:
|
||||||
styledMsgWriteln(color, title, resetStyle, s)
|
styledMsgWriteln(color, title, resetStyle, s)
|
||||||
handleError(msg, doAbort, s)
|
handleError(conf, msg, doAbort, s)
|
||||||
|
|
||||||
proc rawMessage*(msg: TMsgKind, arg: string) =
|
proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) =
|
||||||
rawMessage(msg, [arg])
|
rawMessage(conf, msg, [arg])
|
||||||
|
|
||||||
proc resetAttributes* =
|
proc resetAttributes*(conf: ConfigRef) =
|
||||||
if {optUseColors, optStdout} * gGlobalOptions == {optUseColors}:
|
if {optUseColors, optStdout} * gGlobalOptions == {optUseColors}:
|
||||||
terminal.resetAttributes(stderr)
|
terminal.resetAttributes(stderr)
|
||||||
|
|
||||||
|
|
@ -1005,7 +507,7 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||||
title &
|
title &
|
||||||
getMessageStr(msg, arg)
|
getMessageStr(msg, arg)
|
||||||
|
|
||||||
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||||
eh: TErrorHandling) =
|
eh: TErrorHandling) =
|
||||||
var
|
var
|
||||||
title: string
|
title: string
|
||||||
|
|
@ -1016,7 +518,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||||
case msg
|
case msg
|
||||||
of errMin..errMax:
|
of errMin..errMax:
|
||||||
sev = Severity.Error
|
sev = Severity.Error
|
||||||
writeContext(info)
|
writeContext(conf, info)
|
||||||
title = ErrorTitle
|
title = ErrorTitle
|
||||||
color = ErrorColor
|
color = ErrorColor
|
||||||
# we try to filter error messages so that not two error message
|
# 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
|
lastError = info
|
||||||
of warnMin..warnMax:
|
of warnMin..warnMax:
|
||||||
sev = Severity.Warning
|
sev = Severity.Warning
|
||||||
ignoreMsg = optWarns notin gOptions or msg notin gNotes
|
ignoreMsg = optWarns notin gOptions or msg notin conf.notes
|
||||||
if not ignoreMsg: writeContext(info)
|
if not ignoreMsg: writeContext(conf, info)
|
||||||
title = WarningTitle
|
title = WarningTitle
|
||||||
color = WarningColor
|
color = WarningColor
|
||||||
kind = WarningsToStr[ord(msg) - ord(warnMin)]
|
kind = WarningsToStr[ord(msg) - ord(warnMin)]
|
||||||
inc(gWarnCounter)
|
inc(conf.warnCounter)
|
||||||
of hintMin..hintMax:
|
of hintMin..hintMax:
|
||||||
sev = Severity.Hint
|
sev = Severity.Hint
|
||||||
ignoreMsg = optHints notin gOptions or msg notin gNotes
|
ignoreMsg = optHints notin gOptions or msg notin conf.notes
|
||||||
title = HintTitle
|
title = HintTitle
|
||||||
color = HintColor
|
color = HintColor
|
||||||
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
|
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||||
inc(gHintCounter)
|
inc(conf.hintCounter)
|
||||||
# NOTE: currently line info line numbers start with 1,
|
# NOTE: currently line info line numbers start with 1,
|
||||||
# but column numbers start with 0, however most editors expect
|
# but column numbers start with 0, however most editors expect
|
||||||
# first column to be 1, so we need to +1 here
|
# 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 not ignoreMsg:
|
||||||
if structuredErrorHook != nil:
|
if structuredErrorHook != nil:
|
||||||
structuredErrorHook(info, s & (if kind != nil: KindFormat % kind else: ""), sev)
|
structuredErrorHook(info, s & (if kind != nil: KindFormat % kind else: ""), sev)
|
||||||
if not ignoreMsgBecauseOfIdeTools(msg):
|
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
||||||
if kind != nil:
|
if kind != nil:
|
||||||
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
|
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
|
||||||
KindColor, `%`(KindFormat, kind))
|
KindColor, `%`(KindFormat, kind))
|
||||||
else:
|
else:
|
||||||
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
|
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
|
||||||
if hintSource in gNotes:
|
if hintSource in conf.notes:
|
||||||
info.writeSurroundingSrc
|
info.writeSurroundingSrc()
|
||||||
handleError(msg, eh, s)
|
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'
|
# this fixes bug #7080 so that it is at least obvious 'fatal'
|
||||||
# was executed.
|
# was executed.
|
||||||
errorOutputs = {eStdOut, eStdErr}
|
errorOutputs = {eStdOut, eStdErr}
|
||||||
liMessage(info, msg, arg, doAbort)
|
liMessage(conf, info, msg, arg, doAbort)
|
||||||
|
|
||||||
proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
liMessage(info, msg, arg, doRaise)
|
liMessage(conf, info, msg, arg, doRaise)
|
||||||
|
|
||||||
proc globalError*(info: TLineInfo, arg: string) =
|
proc globalError*(conf: ConfigRef; info: TLineInfo, arg: string) =
|
||||||
liMessage(info, errGenerated, arg, doRaise)
|
liMessage(conf, info, errGenerated, arg, doRaise)
|
||||||
|
|
||||||
proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
proc localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
liMessage(info, msg, arg, doNothing)
|
liMessage(conf, info, msg, arg, doNothing)
|
||||||
|
|
||||||
proc localError*(info: TLineInfo, arg: string) =
|
proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
|
||||||
liMessage(info, errGenerated, arg, doNothing)
|
liMessage(conf, info, errGenerated, arg, doNothing)
|
||||||
|
|
||||||
proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
|
proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openarray[string]) =
|
||||||
localError(info, format % params)
|
localError(conf, info, format % params)
|
||||||
|
|
||||||
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
liMessage(info, msg, arg, doNothing)
|
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
|
if gCmd == cmdIdeTools and structuredErrorHook.isNil: return
|
||||||
writeContext(info)
|
writeContext(conf, info)
|
||||||
liMessage(info, errInternal, errMsg, doAbort)
|
liMessage(conf, info, errInternal, errMsg, doAbort)
|
||||||
|
|
||||||
proc internalError*(errMsg: string) =
|
proc internalError*(conf: ConfigRef; errMsg: string) =
|
||||||
if gCmd == cmdIdeTools and structuredErrorHook.isNil: return
|
if gCmd == cmdIdeTools and structuredErrorHook.isNil: return
|
||||||
writeContext(unknownLineInfo())
|
writeContext(conf, unknownLineInfo())
|
||||||
rawMessage(errInternal, errMsg)
|
rawMessage(conf, errInternal, errMsg)
|
||||||
|
|
||||||
template assertNotNil*(e): untyped =
|
template assertNotNil*(conf, e): untyped =
|
||||||
if e == nil: internalError($instantiationInfo())
|
if e == nil: internalError(conf, $instantiationInfo())
|
||||||
e
|
e
|
||||||
|
|
||||||
template internalAssert*(e: bool) =
|
template internalAssert*(conf, e: bool) =
|
||||||
if not e: internalError($instantiationInfo())
|
if not e: internalError(conf, $instantiationInfo())
|
||||||
|
|
||||||
proc addSourceLine*(fileIdx: FileIndex, line: string) =
|
proc addSourceLine*(fileIdx: FileIndex, line: string) =
|
||||||
fileInfos[fileIdx.int32].lines.add line.rope
|
fileInfos[fileIdx.int32].lines.add line.rope
|
||||||
|
|
@ -1111,14 +613,14 @@ proc sourceLine*(i: TLineInfo): Rope =
|
||||||
addSourceLine i.fileIndex, line.string
|
addSourceLine i.fileIndex, line.string
|
||||||
except IOError:
|
except IOError:
|
||||||
discard
|
discard
|
||||||
internalAssert i.fileIndex.int32 < fileInfos.len
|
assert i.fileIndex.int32 < fileInfos.len
|
||||||
# can happen if the error points to EOF:
|
# can happen if the error points to EOF:
|
||||||
if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil
|
if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil
|
||||||
|
|
||||||
result = fileInfos[i.fileIndex.int32].lines[i.line.int-1]
|
result = fileInfos[i.fileIndex.int32].lines[i.line.int-1]
|
||||||
|
|
||||||
proc quotedFilename*(i: TLineInfo): Rope =
|
proc quotedFilename*(i: TLineInfo): Rope =
|
||||||
internalAssert i.fileIndex.int32 >= 0
|
assert i.fileIndex.int32 >= 0
|
||||||
if optExcessiveStackTrace in gGlobalOptions:
|
if optExcessiveStackTrace in gGlobalOptions:
|
||||||
result = fileInfos[i.fileIndex.int32].quotedFullName
|
result = fileInfos[i.fileIndex.int32].quotedFullName
|
||||||
else:
|
else:
|
||||||
|
|
@ -1127,24 +629,24 @@ proc quotedFilename*(i: TLineInfo): Rope =
|
||||||
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
|
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
|
||||||
case err
|
case err
|
||||||
of rInvalidFormatStr:
|
of rInvalidFormatStr:
|
||||||
internalError("ropes: invalid format string: " & msg)
|
internalError(newConfigRef(), "ropes: invalid format string: " & msg)
|
||||||
of rCannotOpenFile:
|
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:")
|
msgWriteln("Warnings:")
|
||||||
for warn in warnMin..warnMax:
|
for warn in warnMin..warnMax:
|
||||||
msgWriteln(" [$1] $2" % [
|
msgWriteln(" [$1] $2" % [
|
||||||
if warn in gNotes: "x" else: " ",
|
if warn in conf.notes: "x" else: " ",
|
||||||
msgs.WarningsToStr[ord(warn) - ord(warnMin)]
|
configuration.WarningsToStr[ord(warn) - ord(warnMin)]
|
||||||
])
|
])
|
||||||
|
|
||||||
proc listHints*() =
|
proc listHints*(conf: ConfigRef) =
|
||||||
msgWriteln("Hints:")
|
msgWriteln("Hints:")
|
||||||
for hint in hintMin..hintMax:
|
for hint in hintMin..hintMax:
|
||||||
msgWriteln(" [$1] $2" % [
|
msgWriteln(" [$1] $2" % [
|
||||||
if hint in gNotes: "x" else: " ",
|
if hint in conf.notes: "x" else: " ",
|
||||||
msgs.HintsToStr[ord(hint) - ord(hintMin)]
|
configuration.HintsToStr[ord(hint) - ord(hintMin)]
|
||||||
])
|
])
|
||||||
|
|
||||||
# enable colors by default on terminals
|
# enable colors by default on terminals
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ proc prependCurDir(f: string): string =
|
||||||
|
|
||||||
proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
|
proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
|
||||||
if paramCount() == 0:
|
if paramCount() == 0:
|
||||||
writeCommandLineUsage()
|
writeCommandLineUsage(config.helpWritten)
|
||||||
else:
|
else:
|
||||||
# Process command line arguments:
|
# Process command line arguments:
|
||||||
processCmdLine(passCmd1, "", config)
|
processCmdLine(passCmd1, "", config)
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,10 @@
|
||||||
|
|
||||||
## Implements some helper procs for Nimble (Nim's package manager) support.
|
## 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):
|
if not options.searchPaths.contains(path):
|
||||||
options.searchPaths.insert(path, 0)
|
options.searchPaths.insert(path, 0)
|
||||||
|
|
||||||
|
|
@ -84,7 +85,7 @@ proc getPathVersion*(p: string): tuple[name, version: string] =
|
||||||
result.name = p[0 .. sepIdx - 1]
|
result.name = p[0 .. sepIdx - 1]
|
||||||
result.version = p.substr(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)
|
let (name, ver) = getPathVersion(p)
|
||||||
if isValidVersion(ver):
|
if isValidVersion(ver):
|
||||||
let version = newVersion(ver)
|
let version = newVersion(ver)
|
||||||
|
|
@ -92,14 +93,14 @@ proc addPackage(packages: StringTableRef, p: string; info: TLineInfo) =
|
||||||
(not packages.hasKey(name)):
|
(not packages.hasKey(name)):
|
||||||
packages[name] = $version
|
packages[name] = $version
|
||||||
else:
|
else:
|
||||||
localError(info, "invalid package name: " & p)
|
localError(conf, info, "invalid package name: " & p)
|
||||||
|
|
||||||
iterator chosen(packages: StringTableRef): string =
|
iterator chosen(packages: StringTableRef): string =
|
||||||
for key, val in pairs(packages):
|
for key, val in pairs(packages):
|
||||||
let res = if val.len == 0: key else: key & '-' & val
|
let res = if val.len == 0: key else: key & '-' & val
|
||||||
yield res
|
yield res
|
||||||
|
|
||||||
proc addNimblePath(p: string, info: TLineInfo) =
|
proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) =
|
||||||
var path = p
|
var path = p
|
||||||
let nimbleLinks = toSeq(walkPattern(p / "*.nimble-link"))
|
let nimbleLinks = toSeq(walkPattern(p / "*.nimble-link"))
|
||||||
if nimbleLinks.len > 0:
|
if nimbleLinks.len > 0:
|
||||||
|
|
@ -112,22 +113,22 @@ proc addNimblePath(p: string, info: TLineInfo) =
|
||||||
path = p / path
|
path = p / path
|
||||||
|
|
||||||
if not contains(options.searchPaths, path):
|
if not contains(options.searchPaths, path):
|
||||||
message(info, hintPath, path)
|
message(conf, info, hintPath, path)
|
||||||
options.lazyPaths.insert(path, 0)
|
options.lazyPaths.insert(path, 0)
|
||||||
|
|
||||||
proc addPathRec(dir: string, info: TLineInfo) =
|
proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
|
||||||
var packages = newStringTable(modeStyleInsensitive)
|
var packages = newStringTable(modeStyleInsensitive)
|
||||||
var pos = dir.len-1
|
var pos = dir.len-1
|
||||||
if dir[pos] in {DirSep, AltSep}: inc(pos)
|
if dir[pos] in {DirSep, AltSep}: inc(pos)
|
||||||
for k,p in os.walkDir(dir):
|
for k,p in os.walkDir(dir):
|
||||||
if k == pcDir and p[pos] != '.':
|
if k == pcDir and p[pos] != '.':
|
||||||
addPackage(packages, p, info)
|
addPackage(conf, packages, p, info)
|
||||||
for p in packages.chosen:
|
for p in packages.chosen:
|
||||||
addNimblePath(p, info)
|
addNimblePath(conf, p, info)
|
||||||
|
|
||||||
proc nimblePath*(path: string, info: TLineInfo) =
|
proc nimblePath*(conf: ConfigRef; path: string, info: TLineInfo) =
|
||||||
addPathRec(path, info)
|
addPathRec(conf, path, info)
|
||||||
addNimblePath(path, info)
|
addNimblePath(conf, path, info)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
proc v(s: string): Version = s.newVersion
|
proc v(s: string): Version = s.newVersion
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
|
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
|
||||||
options, idents, wordrecg, strtabs
|
options, idents, wordrecg, strtabs, configuration
|
||||||
|
|
||||||
# ---------------- configuration file parser -----------------------------
|
# ---------------- configuration file parser -----------------------------
|
||||||
# we use Nim's scanner here to save space and work
|
# 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)
|
ppGetTok(L, tok)
|
||||||
result = parseExpr(L, tok, config)
|
result = parseExpr(L, tok, config)
|
||||||
if tok.tokType == tkParRi: ppGetTok(L, tok)
|
if tok.tokType == tkParRi: ppGetTok(L, tok)
|
||||||
else: lexMessage(L, errTokenExpected, "\')\'")
|
else: lexMessage(L, errGenerated, "expected closing ')'")
|
||||||
elif tok.ident.id == ord(wNot):
|
elif tok.ident.id == ord(wNot):
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
result = not parseAtom(L, tok, config)
|
result = not parseAtom(L, tok, config)
|
||||||
else:
|
else:
|
||||||
result = isDefined(tok.ident)
|
result = isDefined(config, tok.ident.s)
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
|
|
||||||
proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
|
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'
|
ppGetTok(L, tok) # skip 'if' or 'elif'
|
||||||
result = parseExpr(L, tok, config)
|
result = parseExpr(L, tok, config)
|
||||||
if tok.tokType == tkColon: ppGetTok(L, tok)
|
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) =
|
proc doEnd(L: var TLexer, tok: var TToken; condStack: var seq[bool]) =
|
||||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
|
||||||
ppGetTok(L, tok) # skip 'end'
|
ppGetTok(L, tok) # skip 'end'
|
||||||
setLen(condStack, high(condStack))
|
setLen(condStack, high(condStack))
|
||||||
|
|
||||||
|
|
@ -66,20 +66,22 @@ type
|
||||||
TJumpDest = enum
|
TJumpDest = enum
|
||||||
jdEndif, jdElseEndif
|
jdEndif, jdElseEndif
|
||||||
|
|
||||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef)
|
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
|
||||||
proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
condStack: var seq[bool])
|
||||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
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)
|
ppGetTok(L, tok)
|
||||||
if tok.tokType == tkColon: 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) =
|
proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
|
||||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
|
||||||
var res = evalppIf(L, tok, config)
|
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
|
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
|
var nestedIfs = 0
|
||||||
while true:
|
while true:
|
||||||
if tok.ident != nil and tok.ident.s == "@":
|
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)
|
inc(nestedIfs)
|
||||||
of wElse:
|
of wElse:
|
||||||
if dest == jdElseEndif and nestedIfs == 0:
|
if dest == jdElseEndif and nestedIfs == 0:
|
||||||
doElse(L, tok, config)
|
doElse(L, tok, config, condStack)
|
||||||
break
|
break
|
||||||
of wElif:
|
of wElif:
|
||||||
if dest == jdElseEndif and nestedIfs == 0:
|
if dest == jdElseEndif and nestedIfs == 0:
|
||||||
doElif(L, tok, config)
|
doElif(L, tok, config, condStack)
|
||||||
break
|
break
|
||||||
of wEnd:
|
of wEnd:
|
||||||
if nestedIfs == 0:
|
if nestedIfs == 0:
|
||||||
doEnd(L, tok)
|
doEnd(L, tok, condStack)
|
||||||
break
|
break
|
||||||
if nestedIfs > 0: dec(nestedIfs)
|
if nestedIfs > 0: dec(nestedIfs)
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
elif tok.tokType == tkEof:
|
elif tok.tokType == tkEof:
|
||||||
lexMessage(L, errTokenExpected, "@end")
|
lexMessage(L, errGenerated, "expected @end")
|
||||||
else:
|
else:
|
||||||
ppGetTok(L, tok)
|
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 @
|
ppGetTok(L, tok) # skip @
|
||||||
case whichKeyword(tok.ident)
|
case whichKeyword(tok.ident)
|
||||||
of wIf:
|
of wIf:
|
||||||
setLen(condStack, len(condStack) + 1)
|
setLen(condStack, len(condStack) + 1)
|
||||||
let res = evalppIf(L, tok, config)
|
let res = evalppIf(L, tok, config)
|
||||||
condStack[high(condStack)] = res
|
condStack[high(condStack)] = res
|
||||||
if not res: jumpToDirective(L, tok, jdElseEndif, config)
|
if not res: jumpToDirective(L, tok, jdElseEndif, config, condStack)
|
||||||
of wElif: doElif(L, tok, config)
|
of wElif: doElif(L, tok, config, condStack)
|
||||||
of wElse: doElse(L, tok, config)
|
of wElse: doElse(L, tok, config, condStack)
|
||||||
of wEnd: doEnd(L, tok)
|
of wEnd: doEnd(L, tok, condStack)
|
||||||
of wWrite:
|
of wWrite:
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars,
|
msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars,
|
||||||
|
|
@ -144,53 +146,55 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
|
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
|
||||||
ppGetTok(L, 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)
|
ppGetTok(L, tok)
|
||||||
while tok.ident != nil and tok.ident.s == "@":
|
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) =
|
proc checkSymbol(L: TLexer, tok: TToken) =
|
||||||
if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}:
|
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 == "--":
|
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
|
var info = getLineInfo(L, tok) # save for later in case of an error
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
var s = tokToStr(tok)
|
var s = tokToStr(tok)
|
||||||
confTok(L, tok, config) # skip symbol
|
confTok(L, tok, config, condStack) # skip symbol
|
||||||
var val = ""
|
var val = ""
|
||||||
while tok.tokType == tkDot:
|
while tok.tokType == tkDot:
|
||||||
add(s, '.')
|
add(s, '.')
|
||||||
confTok(L, tok, config)
|
confTok(L, tok, config, condStack)
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
add(s, tokToStr(tok))
|
add(s, tokToStr(tok))
|
||||||
confTok(L, tok, config)
|
confTok(L, tok, config, condStack)
|
||||||
if tok.tokType == tkBracketLe:
|
if tok.tokType == tkBracketLe:
|
||||||
# BUGFIX: val, not s!
|
# BUGFIX: val, not s!
|
||||||
# BUGFIX: do not copy '['!
|
# BUGFIX: do not copy '['!
|
||||||
confTok(L, tok, config)
|
confTok(L, tok, config, condStack)
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
add(val, tokToStr(tok))
|
add(val, tokToStr(tok))
|
||||||
confTok(L, tok, config)
|
confTok(L, tok, config, condStack)
|
||||||
if tok.tokType == tkBracketRi: confTok(L, tok, config)
|
if tok.tokType == tkBracketRi: confTok(L, tok, config, condStack)
|
||||||
else: lexMessage(L, errTokenExpected, "']'")
|
else: lexMessage(L, errGenerated, "expected closing ']'")
|
||||||
add(val, ']')
|
add(val, ']')
|
||||||
let percent = tok.ident != nil and tok.ident.s == "%="
|
let percent = tok.ident != nil and tok.ident.s == "%="
|
||||||
if tok.tokType in {tkColon, tkEquals} or percent:
|
if tok.tokType in {tkColon, tkEquals} or percent:
|
||||||
if len(val) > 0: add(val, ':')
|
if len(val) > 0: add(val, ':')
|
||||||
confTok(L, tok, config) # skip ':' or '=' or '%'
|
confTok(L, tok, config, condStack) # skip ':' or '=' or '%'
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
add(val, tokToStr(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 == "&":
|
while tok.ident != nil and tok.ident.s == "&":
|
||||||
confTok(L, tok, config)
|
confTok(L, tok, config, condStack)
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
add(val, tokToStr(tok))
|
add(val, tokToStr(tok))
|
||||||
confTok(L, tok, config)
|
confTok(L, tok, config, condStack)
|
||||||
if percent:
|
if percent:
|
||||||
processSwitch(s, strtabs.`%`(val, options.gConfigVars,
|
processSwitch(s, strtabs.`%`(val, options.gConfigVars,
|
||||||
{useEnvironment, useEmpty}), passPP, info, config)
|
{useEnvironment, useEmpty}), passPP, info, config)
|
||||||
|
|
@ -207,34 +211,35 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
|
||||||
initToken(tok)
|
initToken(tok)
|
||||||
openLexer(L, filename, stream, cache, config)
|
openLexer(L, filename, stream, cache, config)
|
||||||
tok.tokType = tkEof # to avoid a pointless warning
|
tok.tokType = tkEof # to avoid a pointless warning
|
||||||
confTok(L, tok, config) # read in the first token
|
var condStack: seq[bool] = @[]
|
||||||
while tok.tokType != tkEof: parseAssignment(L, tok, config)
|
confTok(L, tok, config, condStack) # read in the first token
|
||||||
if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
|
while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
|
||||||
|
if len(condStack) > 0: lexMessage(L, errGenerated, "expected @end")
|
||||||
closeLexer(L)
|
closeLexer(L)
|
||||||
rawMessage(hintConf, filename)
|
rawMessage(config, hintConf, filename)
|
||||||
|
|
||||||
proc getUserConfigPath(filename: string): string =
|
proc getUserConfigPath(filename: string): string =
|
||||||
result = joinPath(getConfigDir(), filename)
|
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
|
# try standard configuration file (installation did not distribute files
|
||||||
# the UNIX way)
|
# the UNIX way)
|
||||||
let p = getPrefixDir()
|
let p = getPrefixDir(conf)
|
||||||
result = joinPath([p, "config", filename])
|
result = joinPath([p, "config", filename])
|
||||||
when defined(unix):
|
when defined(unix):
|
||||||
if not existsFile(result): result = joinPath([p, "etc", filename])
|
if not existsFile(result): result = joinPath([p, "etc", filename])
|
||||||
if not existsFile(result): result = "/etc/" & filename
|
if not existsFile(result): result = "/etc/" & filename
|
||||||
|
|
||||||
proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) =
|
proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) =
|
||||||
setDefaultLibpath()
|
setDefaultLibpath(config)
|
||||||
|
|
||||||
if optSkipConfigFile notin gGlobalOptions:
|
if optSkipConfigFile notin gGlobalOptions:
|
||||||
readConfigFile(getSystemConfigPath(cfg), cache, config)
|
readConfigFile(getSystemConfigPath(config, cfg), cache, config)
|
||||||
|
|
||||||
if optSkipUserConfigFile notin gGlobalOptions:
|
if optSkipUserConfigFile notin gGlobalOptions:
|
||||||
readConfigFile(getUserConfigPath(cfg), cache, config)
|
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:
|
if optSkipParentConfigFiles notin gGlobalOptions:
|
||||||
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
|
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
|
||||||
readConfigFile(dir / cfg, cache, config)
|
readConfigFile(dir / cfg, cache, config)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import
|
import
|
||||||
os, strutils, strtabs, osproc, sets
|
os, strutils, strtabs, osproc, sets, configuration, platform
|
||||||
|
|
||||||
const
|
const
|
||||||
hasTinyCBackend* = defined(tinyc)
|
hasTinyCBackend* = defined(tinyc)
|
||||||
|
|
@ -118,16 +118,71 @@ type
|
||||||
features*: set[Feature]
|
features*: set[Feature]
|
||||||
arguments*: string ## the arguments to be passed to the program that
|
arguments*: string ## the arguments to be passed to the program that
|
||||||
## should be run
|
## 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}
|
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
|
||||||
|
|
||||||
proc newConfigRef*(): ConfigRef =
|
proc newConfigRef*(): ConfigRef =
|
||||||
result = ConfigRef(cppDefines: initSet[string](),
|
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) =
|
proc cppDefine*(c: ConfigRef; define: string) =
|
||||||
c.cppDefines.incl define
|
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
|
var
|
||||||
gIdeCmd*: IdeCmd
|
gIdeCmd*: IdeCmd
|
||||||
gOldNewlines*: bool
|
gOldNewlines*: bool
|
||||||
|
|
@ -226,20 +281,20 @@ proc mainCommandArg*: string =
|
||||||
else:
|
else:
|
||||||
result = gProjectName
|
result = gProjectName
|
||||||
|
|
||||||
proc existsConfigVar*(key: string): bool =
|
proc existsConfigVar*(conf: ConfigRef; key: string): bool =
|
||||||
result = hasKey(gConfigVars, key)
|
result = hasKey(gConfigVars, key)
|
||||||
|
|
||||||
proc getConfigVar*(key: string): string =
|
proc getConfigVar*(conf: ConfigRef; key: string): string =
|
||||||
result = gConfigVars.getOrDefault key
|
result = gConfigVars.getOrDefault key
|
||||||
|
|
||||||
proc setConfigVar*(key, val: string) =
|
proc setConfigVar*(conf: ConfigRef; key, val: string) =
|
||||||
gConfigVars[key] = val
|
gConfigVars[key] = val
|
||||||
|
|
||||||
proc getOutFile*(filename, ext: string): string =
|
proc getOutFile*(conf: ConfigRef; filename, ext: string): string =
|
||||||
if options.outFile != "": result = options.outFile
|
if options.outFile != "": result = options.outFile
|
||||||
else: result = changeFileExt(filename, ext)
|
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.
|
## Gets the prefix dir, usually the parent directory where the binary resides.
|
||||||
##
|
##
|
||||||
## This is overridden by some tools (namely nimsuggest) via the ``gPrefixDir``
|
## This is overridden by some tools (namely nimsuggest) via the ``gPrefixDir``
|
||||||
|
|
@ -248,11 +303,11 @@ proc getPrefixDir*(): string =
|
||||||
else:
|
else:
|
||||||
result = splitPath(getAppDir()).head
|
result = splitPath(getAppDir()).head
|
||||||
|
|
||||||
proc setDefaultLibpath*() =
|
proc setDefaultLibpath*(conf: ConfigRef) =
|
||||||
# set default value (can be overwritten):
|
# set default value (can be overwritten):
|
||||||
if libpath == "":
|
if libpath == "":
|
||||||
# choose default libpath:
|
# choose default libpath:
|
||||||
var prefix = getPrefixDir()
|
var prefix = getPrefixDir(conf)
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
if prefix == "/usr": libpath = "/usr/lib/nim"
|
if prefix == "/usr": libpath = "/usr/lib/nim"
|
||||||
elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
|
elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
|
||||||
|
|
@ -263,12 +318,12 @@ proc setDefaultLibpath*() =
|
||||||
# modules and make use of them.
|
# modules and make use of them.
|
||||||
let realNimPath = findExe("nim")
|
let realNimPath = findExe("nim")
|
||||||
# Find out if $nim/../../lib/system.nim exists.
|
# 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
|
if not fileExists(libpath / "system.nim") and
|
||||||
fileExists(parentNimlibPath / "system.nim"):
|
fileExists(parentNimlibPath / "system.nim"):
|
||||||
libpath = parentNimLibPath
|
libpath = parentNimLibPath
|
||||||
|
|
||||||
proc canonicalizePath*(path: string): string =
|
proc canonicalizePath*(conf: ConfigRef; path: string): string =
|
||||||
# on Windows, 'expandFilename' calls getFullPathName which doesn't do
|
# on Windows, 'expandFilename' calls getFullPathName which doesn't do
|
||||||
# case corrections, so we have to use this convoluted way of retrieving
|
# case corrections, so we have to use this convoluted way of retrieving
|
||||||
# the true filename (see tests/modules and Nimble uses 'import Uri' instead
|
# the true filename (see tests/modules and Nimble uses 'import Uri' instead
|
||||||
|
|
@ -280,12 +335,12 @@ proc canonicalizePath*(path: string): string =
|
||||||
else:
|
else:
|
||||||
result = path.expandFilename
|
result = path.expandFilename
|
||||||
|
|
||||||
proc shortenDir*(dir: string): string =
|
proc shortenDir*(conf: ConfigRef; dir: string): string =
|
||||||
## returns the interesting part of a dir
|
## returns the interesting part of a dir
|
||||||
var prefix = gProjectPath & DirSep
|
var prefix = gProjectPath & DirSep
|
||||||
if startsWith(dir, prefix):
|
if startsWith(dir, prefix):
|
||||||
return substr(dir, len(prefix))
|
return substr(dir, len(prefix))
|
||||||
prefix = getPrefixDir() & DirSep
|
prefix = getPrefixDir(conf) & DirSep
|
||||||
if startsWith(dir, prefix):
|
if startsWith(dir, prefix):
|
||||||
return substr(dir, len(prefix))
|
return substr(dir, len(prefix))
|
||||||
result = dir
|
result = dir
|
||||||
|
|
@ -296,42 +351,42 @@ proc removeTrailingDirSep*(path: string): string =
|
||||||
else:
|
else:
|
||||||
result = path
|
result = path
|
||||||
|
|
||||||
proc disableNimblePath*() =
|
proc disableNimblePath*(conf: ConfigRef) =
|
||||||
gNoNimblePath = true
|
gNoNimblePath = true
|
||||||
lazyPaths.setLen(0)
|
lazyPaths.setLen(0)
|
||||||
|
|
||||||
include packagehandling
|
include packagehandling
|
||||||
|
|
||||||
proc getNimcacheDir*: string =
|
proc getNimcacheDir*(conf: ConfigRef): string =
|
||||||
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
|
result = if nimcacheDir.len > 0: nimcacheDir else: shortenDir(conf, gProjectPath) /
|
||||||
genSubDir
|
genSubDir
|
||||||
|
|
||||||
|
|
||||||
proc pathSubs*(p, config: string): string =
|
proc pathSubs*(conf: ConfigRef; p, config: string): string =
|
||||||
let home = removeTrailingDirSep(os.getHomeDir())
|
let home = removeTrailingDirSep(os.getHomeDir())
|
||||||
result = unixToNativePath(p % [
|
result = unixToNativePath(p % [
|
||||||
"nim", getPrefixDir(),
|
"nim", getPrefixDir(conf),
|
||||||
"lib", libpath,
|
"lib", libpath,
|
||||||
"home", home,
|
"home", home,
|
||||||
"config", config,
|
"config", config,
|
||||||
"projectname", options.gProjectName,
|
"projectname", options.gProjectName,
|
||||||
"projectpath", options.gProjectPath,
|
"projectpath", options.gProjectPath,
|
||||||
"projectdir", options.gProjectPath,
|
"projectdir", options.gProjectPath,
|
||||||
"nimcache", getNimcacheDir()])
|
"nimcache", getNimcacheDir(conf)])
|
||||||
if "~/" in result:
|
if "~/" in result:
|
||||||
result = result.replace("~/", home & '/')
|
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"
|
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
|
||||||
var (head, tail) = splitPath(path)
|
var (head, tail) = splitPath(path)
|
||||||
#if len(head) > 0: head = shortenDir(head & dirSep)
|
#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
|
#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)
|
var (head, tail) = splitPath(f)
|
||||||
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
|
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
|
||||||
var subdir = getNimcacheDir() # / head
|
var subdir = getNimcacheDir(conf) # / head
|
||||||
if createSubDir:
|
if createSubDir:
|
||||||
try:
|
try:
|
||||||
createDir(subdir)
|
createDir(subdir)
|
||||||
|
|
@ -341,14 +396,14 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
||||||
result = joinPath(subdir, tail)
|
result = joinPath(subdir, tail)
|
||||||
#echo "completeGeneratedFilePath(", f, ") = ", result
|
#echo "completeGeneratedFilePath(", f, ") = ", result
|
||||||
|
|
||||||
proc rawFindFile(f: string): string =
|
proc rawFindFile(conf: ConfigRef; f: string): string =
|
||||||
for it in searchPaths:
|
for it in searchPaths:
|
||||||
result = joinPath(it, f)
|
result = joinPath(it, f)
|
||||||
if existsFile(result):
|
if existsFile(result):
|
||||||
return result.canonicalizePath
|
return canonicalizePath(conf, result)
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
proc rawFindFile2(f: string): string =
|
proc rawFindFile2(conf: ConfigRef; f: string): string =
|
||||||
for i, it in lazyPaths:
|
for i, it in lazyPaths:
|
||||||
result = joinPath(it, f)
|
result = joinPath(it, f)
|
||||||
if existsFile(result):
|
if existsFile(result):
|
||||||
|
|
@ -356,30 +411,30 @@ proc rawFindFile2(f: string): string =
|
||||||
for j in countDown(i,1):
|
for j in countDown(i,1):
|
||||||
swap(lazyPaths[j], lazyPaths[j-1])
|
swap(lazyPaths[j], lazyPaths[j-1])
|
||||||
|
|
||||||
return result.canonicalizePath
|
return canonicalizePath(conf, result)
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
template patchModule() {.dirty.} =
|
template patchModule(conf: ConfigRef) {.dirty.} =
|
||||||
if result.len > 0 and gModuleOverrides.len > 0:
|
if result.len > 0 and gModuleOverrides.len > 0:
|
||||||
let key = getPackageName(result) & "_" & splitFile(result).name
|
let key = getPackageName(result) & "_" & splitFile(result).name
|
||||||
if gModuleOverrides.hasKey(key):
|
if gModuleOverrides.hasKey(key):
|
||||||
let ov = gModuleOverrides[key]
|
let ov = gModuleOverrides[key]
|
||||||
if ov.len > 0: result = ov
|
if ov.len > 0: result = ov
|
||||||
|
|
||||||
proc findFile*(f: string): string {.procvar.} =
|
proc findFile*(conf: ConfigRef; f: string): string {.procvar.} =
|
||||||
if f.isAbsolute:
|
if f.isAbsolute:
|
||||||
result = if f.existsFile: f else: ""
|
result = if f.existsFile: f else: ""
|
||||||
else:
|
else:
|
||||||
result = f.rawFindFile
|
result = rawFindFile(conf, f)
|
||||||
if result.len == 0:
|
if result.len == 0:
|
||||||
result = f.toLowerAscii.rawFindFile
|
result = rawFindFile(conf, f.toLowerAscii)
|
||||||
if result.len == 0:
|
if result.len == 0:
|
||||||
result = f.rawFindFile2
|
result = rawFindFile2(conf, f)
|
||||||
if result.len == 0:
|
if result.len == 0:
|
||||||
result = f.toLowerAscii.rawFindFile2
|
result = rawFindFile2(conf, f.toLowerAscii)
|
||||||
patchModule()
|
patchModule(conf)
|
||||||
|
|
||||||
proc findModule*(modulename, currentModule: string): string =
|
proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
|
||||||
# returns path to module
|
# returns path to module
|
||||||
when defined(nimfix):
|
when defined(nimfix):
|
||||||
# '.nimfix' modules are preferred over '.nim' modules so that specialized
|
# '.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
|
let currentPath = currentModule.splitFile.dir
|
||||||
result = currentPath / m
|
result = currentPath / m
|
||||||
if not existsFile(result):
|
if not existsFile(result):
|
||||||
result = findFile(m)
|
result = findFile(conf, m)
|
||||||
if existsFile(result): return result
|
if existsFile(result): return result
|
||||||
let m = addFileExt(modulename, NimExt)
|
let m = addFileExt(modulename, NimExt)
|
||||||
let currentPath = currentModule.splitFile.dir
|
let currentPath = currentModule.splitFile.dir
|
||||||
result = currentPath / m
|
result = currentPath / m
|
||||||
if not existsFile(result):
|
if not existsFile(result):
|
||||||
result = findFile(m)
|
result = findFile(conf, m)
|
||||||
patchModule()
|
patchModule(conf)
|
||||||
|
|
||||||
proc findProjectNimFile*(pkg: string): string =
|
proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
|
||||||
const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
|
const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
|
||||||
var candidates: seq[string] = @[]
|
var candidates: seq[string] = @[]
|
||||||
for k, f in os.walkDir(pkg, relative=true):
|
for k, f in os.walkDir(pkg, relative=true):
|
||||||
|
|
@ -423,10 +478,10 @@ proc canonDynlibName(s: string): string =
|
||||||
else:
|
else:
|
||||||
result = s.substr(start)
|
result = s.substr(start)
|
||||||
|
|
||||||
proc inclDynlibOverride*(lib: string) =
|
proc inclDynlibOverride*(conf: ConfigRef; lib: string) =
|
||||||
gDllOverrides[lib.canonDynlibName] = "true"
|
gDllOverrides[lib.canonDynlibName] = "true"
|
||||||
|
|
||||||
proc isDynlibOverride*(lib: string): bool =
|
proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
|
||||||
result = gDynlibOverrideAll or gDllOverrides.hasKey(lib.canonDynlibName)
|
result = gDynlibOverrideAll or gDllOverrides.hasKey(lib.canonDynlibName)
|
||||||
|
|
||||||
proc binaryStrSearch*(x: openArray[string], y: string): int =
|
proc binaryStrSearch*(x: openArray[string], y: string): int =
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ when isMainModule:
|
||||||
outp.close
|
outp.close
|
||||||
|
|
||||||
import
|
import
|
||||||
llstream, lexer, idents, strutils, ast, astalgo, msgs, options
|
llstream, lexer, idents, strutils, ast, astalgo, msgs, options, configuration
|
||||||
|
|
||||||
type
|
type
|
||||||
TParser* = object # A TParser object represents a file that
|
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,
|
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
|
||||||
cache: IdentCache; config: ConfigRef;
|
cache: IdentCache; config: ConfigRef;
|
||||||
strongSpaces=false) =
|
strongSpaces=false) =
|
||||||
openParser(p, filename.fileInfoIdx, inputStream, cache, config, strongSpaces)
|
openParser(p, fileInfoIdx(config, filename), inputStream, cache, config, strongSpaces)
|
||||||
|
|
||||||
proc closeParser(p: var TParser) =
|
proc closeParser(p: var TParser) =
|
||||||
## Close a parser, freeing up its resources.
|
## 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.
|
## Produce and emit the parser message `arg` to output.
|
||||||
lexMessageTok(p.lex, msg, p.tok, arg)
|
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`
|
## 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) =
|
template withInd(p, body: untyped) =
|
||||||
let oldInd = p.currInd
|
let oldInd = p.currInd
|
||||||
|
|
@ -142,6 +146,12 @@ proc skipComment(p: var TParser, node: PNode) =
|
||||||
proc flexComment(p: var TParser, node: PNode) =
|
proc flexComment(p: var TParser, node: PNode) =
|
||||||
if p.tok.indent < 0 or realInd(p): rawSkipComment(p, node)
|
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) =
|
proc skipInd(p: var TParser) =
|
||||||
if p.tok.indent >= 0:
|
if p.tok.indent >= 0:
|
||||||
if not realInd(p): parMessage(p, errInvalidIndentation)
|
if not realInd(p): parMessage(p, errInvalidIndentation)
|
||||||
|
|
@ -160,11 +170,11 @@ proc getTokNoInd(p: var TParser) =
|
||||||
|
|
||||||
proc expectIdentOrKeyw(p: TParser) =
|
proc expectIdentOrKeyw(p: TParser) =
|
||||||
if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
|
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) =
|
proc expectIdent(p: TParser) =
|
||||||
if p.tok.tokType != tkSymbol:
|
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) =
|
proc eat(p: var TParser, tokType: TTokType) =
|
||||||
## Move the parser to the next token if the current token is of type
|
## 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:
|
if p.tok.tokType == tokType:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
else:
|
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 =
|
proc parLineInfo(p: TParser): TLineInfo =
|
||||||
## Retrieve the line information associated with the parser's current state.
|
## Retrieve the line information associated with the parser's current state.
|
||||||
|
|
@ -878,7 +889,7 @@ proc parsePragma(p: var TParser): PNode =
|
||||||
skipComment(p, a)
|
skipComment(p, a)
|
||||||
optPar(p)
|
optPar(p)
|
||||||
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
|
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
|
||||||
else: parMessage(p, errTokenExpected, ".}")
|
else: parMessage(p, "expected '.}'")
|
||||||
dec p.inPragma
|
dec p.inPragma
|
||||||
|
|
||||||
proc identVis(p: var TParser; allowDot=false): PNode =
|
proc identVis(p: var TParser; allowDot=false): PNode =
|
||||||
|
|
@ -939,7 +950,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
|
||||||
else:
|
else:
|
||||||
addSon(result, newNodeP(nkEmpty, p))
|
addSon(result, newNodeP(nkEmpty, p))
|
||||||
if p.tok.tokType != tkEquals and withBothOptional notin flags:
|
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:
|
if p.tok.tokType == tkEquals:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
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'")
|
parMessage(p, errGenerated, "the syntax is 'parameter: var T', not 'var parameter: T'")
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
parMessage(p, errTokenExpected, ")")
|
parMessage(p, "expected closing ')'")
|
||||||
break
|
break
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
||||||
|
|
@ -1173,7 +1184,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
if mode == pmTypeDef:
|
if mode == pmTypeDef:
|
||||||
result = parseTypeClass(p)
|
result = parseTypeClass(p)
|
||||||
else:
|
else:
|
||||||
parMessage(p, errInvalidToken, p.tok)
|
parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
|
||||||
of tkStatic:
|
of tkStatic:
|
||||||
let info = parLineInfo(p)
|
let info = parLineInfo(p)
|
||||||
getTokNoInd(p)
|
getTokNoInd(p)
|
||||||
|
|
@ -1283,7 +1294,7 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
|
||||||
if nextBlock.kind == nkElse: break
|
if nextBlock.kind == nkElse: break
|
||||||
else:
|
else:
|
||||||
if openingParams.kind != nkEmpty:
|
if openingParams.kind != nkEmpty:
|
||||||
parMessage(p, errTokenExpected, ":")
|
parMessage(p, "expected ':'")
|
||||||
|
|
||||||
proc parseExprStmt(p: var TParser): PNode =
|
proc parseExprStmt(p: var TParser): PNode =
|
||||||
#| exprStmt = simpleExpr
|
#| exprStmt = simpleExpr
|
||||||
|
|
@ -1518,7 +1529,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
|
||||||
addSon(b, parseStmt(p))
|
addSon(b, parseStmt(p))
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
if b.kind == nkFinally: break
|
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 =
|
proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
|
||||||
#| exceptBlock = 'except' colcom stmt
|
#| exceptBlock = 'except' colcom stmt
|
||||||
|
|
@ -1573,7 +1584,7 @@ proc parseAsm(p: var TParser): PNode =
|
||||||
of tkTripleStrLit: addSon(result,
|
of tkTripleStrLit: addSon(result,
|
||||||
newStrNodeP(nkTripleStrLit, p.tok.literal, p))
|
newStrNodeP(nkTripleStrLit, p.tok.literal, p))
|
||||||
else:
|
else:
|
||||||
parMessage(p, errStringLiteralExpected)
|
parMessage(p, "the 'asm' statement takes a string literal")
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, ast.emptyNode)
|
||||||
return
|
return
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -1752,7 +1763,7 @@ proc parseEnum(p: var TParser): PNode =
|
||||||
p.tok.tokType == tkEof:
|
p.tok.tokType == tkEof:
|
||||||
break
|
break
|
||||||
if result.len <= 1:
|
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 parseObjectPart(p: var TParser): PNode
|
||||||
proc parseObjectWhen(p: var TParser): PNode =
|
proc parseObjectWhen(p: var TParser): PNode =
|
||||||
|
|
@ -2115,7 +2126,7 @@ proc parseStmt(p: var TParser): PNode =
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc,
|
of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc,
|
||||||
tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar:
|
tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar:
|
||||||
parMessage(p, errComplexStmtRequiresInd)
|
parMessage(p, "complex statement requires indentation")
|
||||||
result = ast.emptyNode
|
result = ast.emptyNode
|
||||||
else:
|
else:
|
||||||
if p.inSemiStmtList > 0:
|
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)
|
processSwitch(a.getString 0, a.getString 1, passPP, module.info, config)
|
||||||
cbconf hintImpl:
|
cbconf hintImpl:
|
||||||
processSpecificNote(a.getString 0, wHint, passPP, module.info,
|
processSpecificNote(a.getString 0, wHint, passPP, module.info,
|
||||||
a.getString 1)
|
a.getString 1, config)
|
||||||
cbconf warningImpl:
|
cbconf warningImpl:
|
||||||
processSpecificNote(a.getString 0, wWarning, passPP, module.info,
|
processSpecificNote(a.getString 0, wWarning, passPP, module.info,
|
||||||
a.getString 1)
|
a.getString 1, config)
|
||||||
cbconf patchFile:
|
cbconf patchFile:
|
||||||
let key = a.getString(0) & "_" & a.getString(1)
|
let key = a.getString(0) & "_" & a.getString(1)
|
||||||
var val = a.getString(2).addFileExt(NimExt)
|
var val = a.getString(2).addFileExt(NimExt)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue