path canonicalization and proper project relative paths
This commit is contained in:
parent
e13a610ad4
commit
e4e74034c2
9 changed files with 61 additions and 47 deletions
|
|
@ -97,7 +97,7 @@ type
|
||||||
next*: ref TToken # for C we need arbitrary look-ahead :-(
|
next*: ref TToken # for C we need arbitrary look-ahead :-(
|
||||||
|
|
||||||
TLexer* = object of TBaseLexer
|
TLexer* = object of TBaseLexer
|
||||||
filename*: string
|
fileIdx*: int32
|
||||||
inDirective: bool
|
inDirective: bool
|
||||||
|
|
||||||
proc getTok*(L: var TLexer, tok: var TToken)
|
proc getTok*(L: var TLexer, tok: var TToken)
|
||||||
|
|
@ -117,7 +117,7 @@ proc fillToken(L: var TToken) =
|
||||||
|
|
||||||
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
||||||
openBaseLexer(lex, inputstream)
|
openBaseLexer(lex, inputstream)
|
||||||
lex.filename = filename
|
lex.fileIdx = filename.fileInfoIdx
|
||||||
|
|
||||||
proc closeLexer*(lex: var TLexer) =
|
proc closeLexer*(lex: var TLexer) =
|
||||||
inc(gLinesCompiled, lex.LineNumber)
|
inc(gLinesCompiled, lex.LineNumber)
|
||||||
|
|
@ -127,13 +127,13 @@ proc getColumn*(L: TLexer): int =
|
||||||
result = getColNumber(L, L.bufPos)
|
result = getColNumber(L, L.bufPos)
|
||||||
|
|
||||||
proc getLineInfo*(L: TLexer): TLineInfo =
|
proc getLineInfo*(L: TLexer): TLineInfo =
|
||||||
result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
|
result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
|
||||||
|
|
||||||
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
|
||||||
msgs.GenericMessage(getLineInfo(L), msg, arg)
|
msgs.GenericMessage(getLineInfo(L), msg, arg)
|
||||||
|
|
||||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||||
var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
|
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
|
||||||
msgs.GenericMessage(info, msg, arg)
|
msgs.GenericMessage(info, msg, arg)
|
||||||
|
|
||||||
proc TokKindToStr*(k: TTokKind): string =
|
proc TokKindToStr*(k: TTokKind): string =
|
||||||
|
|
|
||||||
|
|
@ -459,9 +459,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
||||||
else: InvalidCmdLineOption(pass, switch, info)
|
else: InvalidCmdLineOption(pass, switch, info)
|
||||||
|
|
||||||
proc ProcessCommand(switch: string, pass: TCmdLinePass) =
|
proc ProcessCommand(switch: string, pass: TCmdLinePass) =
|
||||||
var
|
var cmd, arg: string
|
||||||
cmd, arg: string
|
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
|
||||||
var info = newLineInfo("command line", 1, 1)
|
processSwitch(cmd, arg, pass, gCmdLineInfo)
|
||||||
splitSwitch(switch, cmd, arg, pass, info)
|
|
||||||
ProcessSwitch(cmd, arg, pass, info)
|
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ type
|
||||||
# documentation comments are here too
|
# documentation comments are here too
|
||||||
|
|
||||||
TLexer* = object of TBaseLexer
|
TLexer* = object of TBaseLexer
|
||||||
filename*: string
|
fileIdx*: int32
|
||||||
indentStack*: seq[int] # the indentation stack
|
indentStack*: seq[int] # the indentation stack
|
||||||
dedent*: int # counter for DED token generation
|
dedent*: int # counter for DED token generation
|
||||||
indentAhead*: int # if > 0 an indendation has already been read
|
indentAhead*: int # if > 0 an indendation has already been read
|
||||||
|
|
@ -198,7 +198,7 @@ proc fillToken(L: var TToken) =
|
||||||
proc openLexer(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
proc openLexer(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
||||||
openBaseLexer(lex, inputstream)
|
openBaseLexer(lex, inputstream)
|
||||||
lex.indentStack = @[0]
|
lex.indentStack = @[0]
|
||||||
lex.filename = filename
|
lex.fileIdx = filename.fileInfoIdx
|
||||||
lex.indentAhead = - 1
|
lex.indentAhead = - 1
|
||||||
inc(lex.Linenumber, inputstream.lineOffset)
|
inc(lex.Linenumber, inputstream.lineOffset)
|
||||||
|
|
||||||
|
|
@ -210,13 +210,13 @@ proc getColumn(L: TLexer): int =
|
||||||
result = getColNumber(L, L.bufPos)
|
result = getColNumber(L, L.bufPos)
|
||||||
|
|
||||||
proc getLineInfo(L: TLexer): TLineInfo =
|
proc getLineInfo(L: TLexer): TLineInfo =
|
||||||
result = newLineInfo(L.filename, L.linenumber, getColNumber(L, L.bufpos))
|
result = newLineInfo(L.fileIdx, L.linenumber, getColNumber(L, L.bufpos))
|
||||||
|
|
||||||
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
|
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
|
||||||
msgs.Message(getLineInfo(L), msg, arg)
|
msgs.Message(getLineInfo(L), msg, arg)
|
||||||
|
|
||||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||||
var info = newLineInfo(L.filename, L.linenumber, pos - L.lineStart)
|
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
|
||||||
msgs.Message(info, msg, arg)
|
msgs.Message(info, msg, arg)
|
||||||
|
|
||||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ proc CommandSuggest =
|
||||||
|
|
||||||
proc wantMainModule =
|
proc wantMainModule =
|
||||||
if gProjectFull.len == 0:
|
if gProjectFull.len == 0:
|
||||||
Fatal(newLineInfo("command line", 1, 1), errCommandExpectsFilename)
|
Fatal(gCmdLineInfo, errCommandExpectsFilename)
|
||||||
|
|
||||||
proc MainCommand =
|
proc MainCommand =
|
||||||
appendStr(searchPaths, options.libpath)
|
appendStr(searchPaths, options.libpath)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import
|
import
|
||||||
options, strutils, os
|
options, strutils, os, tables
|
||||||
|
|
||||||
type
|
type
|
||||||
TMsgKind* = enum
|
TMsgKind* = enum
|
||||||
|
|
@ -384,6 +384,11 @@ const
|
||||||
type
|
type
|
||||||
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
|
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
|
||||||
TNoteKinds* = set[TNoteKind]
|
TNoteKinds* = set[TNoteKind]
|
||||||
|
|
||||||
|
TFileInfo*{.final.} = object
|
||||||
|
fullPath*: string # This is a canonical full filesystem path
|
||||||
|
projPath*: string # This is relative to the project's root
|
||||||
|
|
||||||
TLineInfo*{.final.} = object # This is designed to be as small as possible,
|
TLineInfo*{.final.} = object # This is designed to be as small as possible,
|
||||||
# because it is used
|
# because it is used
|
||||||
# in syntax nodes. We safe space here by using
|
# in syntax nodes. We safe space here by using
|
||||||
|
|
@ -395,7 +400,37 @@ type
|
||||||
|
|
||||||
ERecoverableError* = object of EInvalidValue
|
ERecoverableError* = object of EInvalidValue
|
||||||
|
|
||||||
proc newLineInfo*(filename: string, line, col: int): TLineInfo
|
var
|
||||||
|
filenameToIndexTbl = initTable[string, int32]()
|
||||||
|
fileInfos: seq[TFileInfo] = @[]
|
||||||
|
|
||||||
|
proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
||||||
|
result.fullPath = fullPath
|
||||||
|
result.projPath = projPath
|
||||||
|
|
||||||
|
proc fileInfoIdx*(filename: string): int32 =
|
||||||
|
var canonical = canonicalizePath(filename)
|
||||||
|
|
||||||
|
if filenameToIndexTbl.hasKey(canonical):
|
||||||
|
result = filenameToIndexTbl[canonical]
|
||||||
|
else:
|
||||||
|
result = fileInfos.len.int32
|
||||||
|
fileInfos.add(newFileInfo(canonical, canonical.shortenDir))
|
||||||
|
filenameToIndexTbl[canonical] = result
|
||||||
|
|
||||||
|
proc newLineInfo*(filename: string, line, col: int): TLineInfo =
|
||||||
|
result.fileIndex = filename.fileInfoIdx
|
||||||
|
result.line = int16(line)
|
||||||
|
result.col = int16(col)
|
||||||
|
|
||||||
|
proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
|
||||||
|
result.fileIndex = fileInfoIdx
|
||||||
|
result.line = int16(line)
|
||||||
|
result.col = int16(col)
|
||||||
|
|
||||||
|
fileInfos.add(newFileInfo("command line", ""))
|
||||||
|
var gCmdLineInfo* = newLineInfo(int32(0), 1, 1)
|
||||||
|
|
||||||
proc raiseRecoverableError*() {.noinline, noreturn.} =
|
proc raiseRecoverableError*() {.noinline, noreturn.} =
|
||||||
raise newException(ERecoverableError, "")
|
raise newException(ERecoverableError, "")
|
||||||
|
|
||||||
|
|
@ -423,9 +458,7 @@ proc UnknownLineInfo*(): TLineInfo =
|
||||||
result.fileIndex = -1
|
result.fileIndex = -1
|
||||||
|
|
||||||
var
|
var
|
||||||
filenames: seq[tuple[filename: string, fullpath: string]] = @[]
|
|
||||||
msgContext: seq[TLineInfo] = @[]
|
msgContext: seq[TLineInfo] = @[]
|
||||||
gCmdLineInfo* = newLineInfo("command line", -1, -1)
|
|
||||||
|
|
||||||
proc pushInfoContext*(info: TLineInfo) =
|
proc pushInfoContext*(info: TLineInfo) =
|
||||||
msgContext.add(info)
|
msgContext.add(info)
|
||||||
|
|
@ -433,31 +466,13 @@ proc pushInfoContext*(info: TLineInfo) =
|
||||||
proc popInfoContext*() =
|
proc popInfoContext*() =
|
||||||
setlen(msgContext, len(msgContext) - 1)
|
setlen(msgContext, len(msgContext) - 1)
|
||||||
|
|
||||||
proc includeFilename*(f: string): int =
|
proc ToFilename*(info: TLineInfo): string =
|
||||||
for i in countdown(high(filenames), low(filenames)):
|
|
||||||
if filenames[i].filename == f:
|
|
||||||
return i
|
|
||||||
|
|
||||||
result = len(filenames)
|
|
||||||
|
|
||||||
var fullpath: string
|
|
||||||
try: fullpath = expandFilename(f)
|
|
||||||
except: fullpath = ""
|
|
||||||
|
|
||||||
filenames.add((filename: f, fullpath: fullpath))
|
|
||||||
|
|
||||||
proc newLineInfo(filename: string, line, col: int): TLineInfo =
|
|
||||||
result.fileIndex = includeFilename(filename)
|
|
||||||
result.line = int16(line)
|
|
||||||
result.col = int16(col)
|
|
||||||
|
|
||||||
proc ToFilename*(info: TLineInfo): string =
|
|
||||||
if info.fileIndex < 0: result = "???"
|
if info.fileIndex < 0: result = "???"
|
||||||
else: result = filenames[info.fileIndex].filename
|
else: result = fileInfos[info.fileIndex].projPath
|
||||||
|
|
||||||
proc toFullPath*(info: TLineInfo): string =
|
proc toFullPath*(info: TLineInfo): string =
|
||||||
if info.fileIndex < 0: result = "???"
|
if info.fileIndex < 0: result = "???"
|
||||||
else: result = filenames[info.fileIndex].fullpath
|
else: result = fileInfos[info.fileIndex].fullPath
|
||||||
|
|
||||||
proc ToLinenumber*(info: TLineInfo): int {.inline.} =
|
proc ToLinenumber*(info: TLineInfo): int {.inline.} =
|
||||||
result = info.line
|
result = info.line
|
||||||
|
|
|
||||||
|
|
@ -70,14 +70,14 @@ proc HandleCmdLine() =
|
||||||
ProcessCmdLine(passCmd1)
|
ProcessCmdLine(passCmd1)
|
||||||
if gProjectName != "":
|
if gProjectName != "":
|
||||||
try:
|
try:
|
||||||
gProjectFull = expandFilename(gProjectName)
|
gProjectFull = canonicalizePath(gProjectName)
|
||||||
except EOS:
|
except EOS:
|
||||||
gProjectFull = gProjectName
|
gProjectFull = gProjectName
|
||||||
var p = splitFile(gProjectFull)
|
var p = splitFile(gProjectFull)
|
||||||
gProjectPath = p.dir
|
gProjectPath = p.dir
|
||||||
gProjectName = p.name
|
gProjectName = p.name
|
||||||
else:
|
else:
|
||||||
gProjectPath = getCurrentDir()
|
gProjectPath = getCurrentDir()
|
||||||
LoadConfigs(DefaultConfig) # load all config files
|
LoadConfigs(DefaultConfig) # load all config files
|
||||||
# now process command line arguments again, because some options in the
|
# now process command line arguments again, because some options in the
|
||||||
# command line can overwite the config file's settings
|
# command line can overwite the config file's settings
|
||||||
|
|
|
||||||
|
|
@ -138,12 +138,13 @@ proc getPrefixDir*(): string =
|
||||||
## gets the application directory
|
## gets the application directory
|
||||||
result = SplitPath(getAppDir()).head
|
result = SplitPath(getAppDir()).head
|
||||||
|
|
||||||
|
proc canonicalizePath*(path: string): string =
|
||||||
|
result = path.expandFilename
|
||||||
|
when not FileSystemCaseSensitive: result = result.toLower
|
||||||
|
|
||||||
proc shortenDir*(dir: string): string =
|
proc shortenDir*(dir: string): string =
|
||||||
## returns the interesting part of a dir
|
## returns the interesting part of a dir
|
||||||
var prefix = getPrefixDir() & dirSep
|
var prefix = getPrefixDir() & dirSep
|
||||||
if startsWith(dir, prefix):
|
|
||||||
return substr(dir, len(prefix))
|
|
||||||
prefix = getCurrentDir() & dirSep
|
|
||||||
if startsWith(dir, prefix):
|
if startsWith(dir, prefix):
|
||||||
return substr(dir, len(prefix))
|
return substr(dir, len(prefix))
|
||||||
prefix = gProjectPath & dirSep
|
prefix = gProjectPath & dirSep
|
||||||
|
|
|
||||||
|
|
@ -796,7 +796,7 @@ proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
addSon(result, n)
|
addSon(result, n)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var f = getModuleFile(n.sons[i])
|
var f = getModuleFile(n.sons[i])
|
||||||
var fileIndex = includeFilename(f)
|
var fileIndex = f.fileInfoIdx
|
||||||
if ContainsOrIncl(c.includedFiles, fileIndex):
|
if ContainsOrIncl(c.includedFiles, fileIndex):
|
||||||
GlobalError(n.info, errRecursiveDependencyX, f)
|
GlobalError(n.info, errRecursiveDependencyX, f)
|
||||||
addSon(result, semStmt(c, gIncludeFile(f)))
|
addSon(result, semStmt(c, gIncludeFile(f)))
|
||||||
|
|
|
||||||
|
|
@ -713,7 +713,7 @@ proc matches*(c: PContext, n: PNode, m: var TCandidate) =
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
if sfSystemModule notin c.module.flags:
|
if sfSystemModule notin c.module.flags:
|
||||||
if includeFilename("temp.nim") == c.module.info.fileIndex:
|
if fileInfoIdx("temp.nim") == c.module.info.fileIndex:
|
||||||
echo "########################"
|
echo "########################"
|
||||||
echo m.call.renderTree
|
echo m.call.renderTree
|
||||||
for i in 1..m.call.len-1:
|
for i in 1..m.call.len-1:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue