Merge branch 'master' into newparser

This commit is contained in:
Araq 2013-05-07 18:44:24 +02:00
commit 9fc98cefda
18 changed files with 196 additions and 69 deletions

View file

@ -275,6 +275,7 @@ const
sfDirty* = sfPure sfDirty* = sfPure
# template is not hygienic (old styled template) # template is not hygienic (old styled template)
# module, compiled from a dirty-buffer
sfAnon* = sfDiscardable sfAnon* = sfDiscardable
# symbol name that was generated by the compiler # symbol name that was generated by the compiler
@ -680,7 +681,6 @@ type
size*: BiggestInt # the size of the type in bytes size*: BiggestInt # the size of the type in bytes
# -1 means that the size is unkwown # -1 means that the size is unkwown
align*: int # the type's alignment requirements align*: int # the type's alignment requirements
containerID*: int # used for type checking of generics
loc*: TLoc loc*: TLoc
TPair*{.final.} = object TPair*{.final.} = object
@ -1020,7 +1020,6 @@ proc assignType(dest, src: PType) =
dest.n = src.n dest.n = src.n
dest.size = src.size dest.size = src.size
dest.align = src.align dest.align = src.align
dest.containerID = src.containerID
dest.destructor = src.destructor dest.destructor = src.destructor
# this fixes 'type TLock = TSysLock': # this fixes 'type TLock = TSysLock':
if src.sym != nil: if src.sym != nil:

View file

@ -1279,10 +1279,6 @@ proc updateCachedModule(m: BModule) =
addFileToLink(cfilenoext) addFileToLink(cfilenoext)
proc updateCachedModules* =
for m in cgenModules():
if m.fromCache: m.updateCachedModule
proc myClose(b: PPassContext, n: PNode): PNode = proc myClose(b: PPassContext, n: PNode): PNode =
result = n result = n
if b == nil or passes.skipCodegen(n): return if b == nil or passes.skipCodegen(n): return
@ -1292,24 +1288,28 @@ proc myClose(b: PPassContext, n: PNode): PNode =
genStmts(m.initProc, n) genStmts(m.initProc, n)
# cached modules need to registered too: # cached modules need to registered too:
registerModuleToMain(m.module) registerModuleToMain(m.module)
if sfMainModule in m.module.flags: if sfMainModule in m.module.flags:
var disp = generateMethodDispatchers() var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym) for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
genMainProc(m) genMainProc(m)
# we need to process the transitive closure because recursive module
# deps are allowed (and the system module is processed in the wrong proc cgenWriteModules* =
# order anyway) # we need to process the transitive closure because recursive module
if generatedHeader != nil: finishModule(generatedHeader) # deps are allowed (and the system module is processed in the wrong
while gForwardedProcsCounter > 0: # order anyway)
for m in cgenModules(): if generatedHeader != nil: finishModule(generatedHeader)
if not m.fromCache: while gForwardedProcsCounter > 0:
finishModule(m)
for m in cgenModules(): for m in cgenModules():
if not m.fromCache: if not m.fromCache:
writeModule(m, pending=true) finishModule(m)
writeMapping(gMapping) for m in cgenModules():
if generatedHeader != nil: writeHeader(generatedHeader) if m.fromCache:
m.updateCachedModule
else:
m.writeModule(pending=true)
writeMapping(gMapping)
if generatedHeader != nil: writeHeader(generatedHeader)
const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose) const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)

View file

@ -207,6 +207,22 @@ proc processPath(path: string, notRelativeToProj = false): string =
"projectname", options.gProjectName, "projectname", options.gProjectName,
"projectpath", options.gProjectPath]) "projectpath", options.gProjectPath])
proc trackDirty(arg: string, info: TLineInfo) =
var a = arg.split(',')
if a.len != 4: LocalError(info, errTokenExpected,
"DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN")
var line, column: int
if parseUtils.parseInt(a[2], line) <= 0:
LocalError(info, errInvalidNumber, a[1])
if parseUtils.parseInt(a[3], column) <= 0:
LocalError(info, errInvalidNumber, a[2])
gDirtyBufferIdx = a[0].fileInfoIdx
gDirtyOriginalIdx = a[1].fileInfoIdx
optTrackPos = newLineInfo(gDirtyBufferIdx, line, column)
msgs.addCheckpoint(optTrackPos)
proc track(arg: string, info: TLineInfo) = proc track(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(info, errTokenExpected, "FILE,LINE,COLUMN")
@ -215,7 +231,8 @@ proc track(arg: string, info: TLineInfo) =
LocalError(info, errInvalidNumber, a[1]) LocalError(info, errInvalidNumber, a[1])
if parseUtils.parseInt(a[2], column) <= 0: if parseUtils.parseInt(a[2], column) <= 0:
LocalError(info, errInvalidNumber, a[2]) LocalError(info, errInvalidNumber, a[2])
msgs.addCheckpoint(newLineInfo(a[0], line, column)) optTrackPos = newLineInfo(a[0], line, column)
msgs.addCheckpoint(optTrackPos)
proc dynlibOverride(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) = proc dynlibOverride(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
if pass in {passCmd2, passPP}: if pass in {passCmd2, passPP}:
@ -469,6 +486,9 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "track": of "track":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
track(arg, info) track(arg, info)
of "trackdirty":
expectArg(switch, arg, pass, info)
trackDirty(arg, info)
of "suggest": of "suggest":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSuggest) incl(gGlobalOptions, optSuggest)

View file

@ -579,7 +579,7 @@ proc CallCCompiler*(projectfile: string) =
else: else:
rawMessage(errGenerated, " execution of an external program failed; " & rawMessage(errGenerated, " execution of an external program failed; " &
"rerun with --parallelBuild:1 to see the error message") "rerun with --parallelBuild:1 to see the error message")
if optNoLinking notin gGlobalOptions: if optNoLinking notin gGlobalOptions and cmds.len > 0:
# call the linker: # call the linker:
var it = PStrEntry(toLink.head) var it = PStrEntry(toLink.head)
var objfiles = "" var objfiles = ""

View file

@ -16,7 +16,7 @@ import
wordrecg, sem, semdata, idents, passes, docgen, extccomp, wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, jsgen, cgendata, json, nversion, cgen, jsgen, cgendata, json, nversion,
platform, nimconf, importer, passaux, depends, evals, types, idgen, platform, nimconf, importer, passaux, depends, evals, types, idgen,
tables, docgen2, service, magicsys, parser, crc, ccgutils tables, docgen2, service, magicsys, parser, crc, ccgutils, sigmatch
const const
has_LLVM_Backend = false has_LLVM_Backend = false
@ -64,7 +64,7 @@ proc crcChanged(fileIdx: int32): bool =
gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
else: crcNotChanged else: crcNotChanged
# echo "TESTING CRC: ", fileIdx.toFilename, " ", result # echo "TESTING CRC: ", fileIdx.toFilename, " ", result
case gMemCacheData[fileIdx].crcStatus: case gMemCacheData[fileIdx].crcStatus:
of crcHasChanged: of crcHasChanged:
result = true result = true
@ -89,38 +89,38 @@ proc addDep(x: Psym, dep: int32) =
growCache gMemCacheData, dep growCache gMemCacheData, dep
gMemCacheData[x.position].deps.safeAdd(dep) gMemCacheData[x.position].deps.safeAdd(dep)
proc ResetModule(fileIdx: int32) = proc resetModule(fileIdx: int32) =
echo "HARD RESETTING ", fileIdx.toFilename # echo "HARD RESETTING ", fileIdx.toFilename
gMemCacheData[fileIdx].needsRecompile = Yes gMemCacheData[fileIdx].needsRecompile = Yes
gCompiledModules[fileIdx] = nil gCompiledModules[fileIdx] = nil
cgendata.gModules[fileIdx] = nil cgendata.gModules[fileIdx] = nil
resetSourceMap(fileIdx)
proc ResetAllModules = proc resetAllModules =
for i in 0..gCompiledModules.high: for i in 0..gCompiledModules.high:
if gCompiledModules[i] != nil: if gCompiledModules[i] != nil:
ResetModule(i.int32) resetModule(i.int32)
for m in cgenModules(): # for m in cgenModules(): echo "CGEN MODULE FOUND"
echo "CGEN MODULE FOUND"
proc checkDepMem(fileIdx: int32): TNeedRecompile = proc checkDepMem(fileIdx: int32): TNeedRecompile =
template markDirty = template markDirty =
ResetModule(fileIdx) resetModule(fileIdx)
return Yes return Yes
if gMemCacheData[fileIdx].needsRecompile != Maybe: if gMemCacheData[fileIdx].needsRecompile != Maybe:
return gMemCacheData[fileIdx].needsRecompile return gMemCacheData[fileIdx].needsRecompile
if optForceFullMake in gGlobalOptions or if optForceFullMake in gGlobalOptions or
curCaasCmd != lastCaasCmd or crcChanged(fileIdx):
crcChanged(fileIdx): markDirty markDirty
if gMemCacheData[fileIdx].deps != nil: if gMemCacheData[fileIdx].deps != nil:
gMemCacheData[fileIdx].needsRecompile = Probing gMemCacheData[fileIdx].needsRecompile = Probing
for dep in gMemCacheData[fileIdx].deps: for dep in gMemCacheData[fileIdx].deps:
let d = checkDepMem(dep) let d = checkDepMem(dep)
if d in { Yes, Recompiled }: if d in { Yes, Recompiled }:
echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
markDirty markDirty
gMemCacheData[fileIdx].needsRecompile = No gMemCacheData[fileIdx].needsRecompile = No
@ -213,6 +213,9 @@ proc rodPass =
if optSymbolFiles in gGlobalOptions: if optSymbolFiles in gGlobalOptions:
registerPass(rodwritePass) registerPass(rodwritePass)
proc codegenPass =
registerPass cgenPass
proc semanticPasses = proc semanticPasses =
registerPass verbosePass registerPass verbosePass
registerPass semPass registerPass semPass
@ -251,14 +254,11 @@ proc CommandCompileToC =
# echo "CHECK DEP COMPLETE" # echo "CHECK DEP COMPLETE"
compileProject() compileProject()
cgenWriteModules()
if compilationCachePresent:
updateCachedModules()
if gCmd != cmdRun: if gCmd != cmdRun:
extccomp.CallCCompiler(changeFileExt(gProjectFull, "")) extccomp.CallCCompiler(changeFileExt(gProjectFull, ""))
if optCaasEnabled in gGlobalOptions: if isServing:
# caas will keep track only of the compilation commands # caas will keep track only of the compilation commands
lastCaasCmd = curCaasCmd lastCaasCmd = curCaasCmd
resetCgenModules() resetCgenModules()
@ -377,10 +377,23 @@ proc CommandScan =
rawMessage(errCannotOpenFile, f) rawMessage(errCannotOpenFile, f)
proc CommandSuggest = proc CommandSuggest =
msgs.gErrorMax = high(int) # do not stop after first error if isServing:
semanticPasses() # XXX: hacky work-around ahead
rodPass() # Currently, it's possible to issue a idetools command, before
compileProject() # issuing the first compile command. This will leave the compiler
# cache in a state where "no recompilation is necessary", but the
# cgen pass was never executed at all.
CommandCompileToC()
if gDirtyBufferIdx != 0:
discard compileModule(gDirtyBufferIdx, {sfDirty})
resetModule(gDirtyBufferIdx)
if optDef in gGlobalOptions:
defFromSourceMap(optTrackPos)
else:
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses()
rodPass()
compileProject()
proc wantMainModule = proc wantMainModule =
if gProjectFull.len == 0: if gProjectFull.len == 0:
@ -404,7 +417,7 @@ proc requireMainModuleOption =
proc resetMemory = proc resetMemory =
resetCompilationLists() resetCompilationLists()
ccgutils.resetCaches() ccgutils.resetCaches()
ResetAllModules() resetAllModules()
resetRopeCache() resetRopeCache()
resetSysTypes() resetSysTypes()
gOwners = @[] gOwners = @[]

View file

@ -526,13 +526,17 @@ proc SuggestWriteln*(s: string) =
else: else:
Writeln(stdout, s) Writeln(stdout, s)
stdoutSocket.send(s & "\c\L") stdoutSocket.send(s & "\c\L")
proc SuggestQuit*() = proc SuggestQuit*() =
if not isServing: quit(0) if not isServing:
elif not isNil(stdoutSocket): quit(0)
stdoutSocket.send("\c\L") elif isWorkingWithDirtyBuffer:
# No need to compile the rest if we are working with a
# throw-away buffer. Incomplete dot expressions frequently
# found in dirty buffers will result in errors few steps
# from now anyway.
raise newException(ESuggestDone, "suggest done") raise newException(ESuggestDone, "suggest done")
# this format is understood by many text editors: it is the same that # this format is understood by many text editors: it is the same that
# Borland and Freepascal use # Borland and Freepascal use
const const
@ -606,6 +610,7 @@ proc `??`* (info: TLineInfo, filename: string): bool =
result = filename in info.toFilename result = filename in info.toFilename
var checkPoints*: seq[TLineInfo] = @[] var checkPoints*: seq[TLineInfo] = @[]
var optTrackPos*: TLineInfo
proc addCheckpoint*(info: TLineInfo) = proc addCheckpoint*(info: TLineInfo) =
checkPoints.add(info) checkPoints.add(info)

View file

@ -107,10 +107,16 @@ var
gLastCmdTime*: float # when caas is enabled, we measure each command gLastCmdTime*: float # when caas is enabled, we measure each command
gListFullPaths*: bool gListFullPaths*: bool
isServing*: bool = false isServing*: bool = false
gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of
# the tracked source X, saved by the CAAS client.
gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer.
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
template isWorkingWithDirtyBuffer*: expr =
gDirtyBufferIdx != 0
template compilationCachePresent*: expr = template compilationCachePresent*: expr =
{optCaasEnabled, optSymbolFiles} * gGlobalOptions != {} {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}

View file

@ -328,9 +328,6 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
result.align = decodeVInt(r.s, r.pos) result.align = decodeVInt(r.s, r.pos)
else: else:
result.align = 2 result.align = 2
if r.s[r.pos] == '@':
inc(r.pos)
result.containerID = decodeVInt(r.s, r.pos)
decodeLoc(r, result.loc, info) decodeLoc(r, result.loc, info)
while r.s[r.pos] == '^': while r.s[r.pos] == '^':
inc(r.pos) inc(r.pos)
@ -1012,9 +1009,6 @@ proc writeType(f: TFile; t: PType) =
if t.align != 2: if t.align != 2:
f.write('=') f.write('=')
f.write($t.align) f.write($t.align)
if t.containerID != 0:
f.write('@')
f.write($t.containerID)
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil: if t.sons[i] == nil:
f.write("^()") f.write("^()")

View file

@ -233,9 +233,6 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
if t.align != 2: if t.align != 2:
add(result, '=') add(result, '=')
encodeVInt(t.align, result) encodeVInt(t.align, result)
if t.containerID != 0:
add(result, '@')
encodeVInt(t.containerID, result)
encodeLoc(w, t.loc, result) encodeLoc(w, t.loc, result)
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil: if t.sons[i] == nil:

View file

@ -693,9 +693,6 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
openScope(c.tab) openScope(c.tab)
pushOwner(s) pushOwner(s)
if s.magic == mNone: s.typ.kind = tyGenericBody if s.magic == mNone: s.typ.kind = tyGenericBody
if s.typ.containerID != 0:
InternalError(a.info, "semTypeSection: containerID")
s.typ.containerID = s.typ.id
# XXX for generic type aliases this is not correct! We need the # XXX for generic type aliases this is not correct! We need the
# underlying Id really: # underlying Id really:
# #

View file

@ -770,9 +770,6 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
return newOrPrevType(tyError, prev, c) return newOrPrevType(tyError, prev, c)
elif s.typ.kind != tyGenericBody: elif s.typ.kind != tyGenericBody:
isConcrete = false isConcrete = false
elif s.typ.containerID == 0:
InternalError(n.info, "semtypes.semGeneric")
return newOrPrevType(tyError, prev, c)
elif sonsLen(n) != sonsLen(s.typ): elif sonsLen(n) != sonsLen(s.typ):
LocalError(n.info, errWrongNumberOfArguments) LocalError(n.info, errWrongNumberOfArguments)
return newOrPrevType(tyError, prev, c) return newOrPrevType(tyError, prev, c)

View file

@ -65,6 +65,9 @@ proc serve*(action: proc (){.nimcall.}) =
curCaasCmd = cmd curCaasCmd = cmd
processCmdLine(passCmd2, cmd) processCmdLine(passCmd2, cmd)
action() action()
gDirtyBufferIdx = 0
gDirtyOriginalIdx = 0
gErrorCounter = 0
let typ = getConfigVar("server.type") let typ = getConfigVar("server.type")
case typ case typ

View file

@ -559,11 +559,10 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
# simply no match for now: # simply no match for now:
nil nil
elif x.kind == tyGenericInst and elif x.kind == tyGenericInst and
(f.sons[0].containerID == x.sons[0].containerID) and (f.sons[0] == x.sons[0]) and
(sonsLen(x) - 1 == sonsLen(f)): (sonsLen(x) - 1 == sonsLen(f)):
assert(x.sons[0].kind == tyGenericBody) for i in countup(1, sonsLen(f) - 1):
for i in countup(1, sonsLen(f) - 1): if x.sons[i].kind == tyGenericParam:
if x.sons[i].kind == tyGenericParam:
InternalError("wrong instantiated type!") InternalError("wrong instantiated type!")
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
result = isGeneric result = isGeneric

View file

@ -9,7 +9,9 @@
## This file implements features required for IDE support. ## This file implements features required for IDE support.
# imported from sigmatch.nim # included from sigmatch.nim
import algorithm
const const
sep = '\t' sep = '\t'
@ -238,12 +240,69 @@ proc findDefinition(node: PNode, s: PSym) =
SuggestWriteln(SymToStr(s, isLocal=false, sectionDef)) SuggestWriteln(SymToStr(s, isLocal=false, sectionDef))
SuggestQuit() SuggestQuit()
type
TSourceMap = object
lines: seq[TLineMap]
TEntry = object
pos: int
sym: PSym
TLineMap = object
entries: seq[TEntry]
var
gSourceMaps: seq[TSourceMap] = @[]
proc ensureIdx[T](x: var T, y: int) =
if x.len <= y: x.setLen(y+1)
proc ensureSeq[T](x: var seq[T]) =
if x == nil: newSeq(x, 0)
proc resetSourceMap*(fileIdx: int32) =
ensureIdx(gSourceMaps, fileIdx)
gSourceMaps[fileIdx].lines = @[]
proc addToSourceMap(sym: Psym, info: TLineInfo) =
ensureIdx(gSourceMaps, info.fileIndex)
ensureSeq(gSourceMaps[info.fileIndex].lines)
ensureIdx(gSourceMaps[info.fileIndex].lines, info.line)
ensureSeq(gSourceMaps[info.fileIndex].lines[info.line].entries)
gSourceMaps[info.fileIndex].lines[info.line].entries.add(TEntry(pos: info.col, sym: sym))
proc defFromLine(entries: var seq[TEntry], col: int32) =
if entries == nil: return
# The sorting is done lazily here on purpose.
# No need to pay the price for it unless the user requests
# "goto definition" on a particular line
sort(entries) do (a,b: TEntry) -> int:
return cmp(a.pos, b.pos)
for e in entries:
# currently, the line-infos for most expressions point to
# one position past the end of the expression. This means
# that the first expr that ends after the cursor column is
# the one we are looking for.
if e.pos >= col:
SuggestWriteln(SymToStr(e.sym, isLocal=false, sectionDef))
return
proc defFromSourceMap*(i: TLineInfo) =
if not ((i.fileIndex < gSourceMaps.len) and
(gSourceMaps[i.fileIndex].lines != nil) and
(i.line < gSourceMaps[i.fileIndex].lines.len)): return
defFromLine(gSourceMaps[i.fileIndex].lines[i.line].entries, i.col)
proc suggestSym*(n: PNode, s: PSym) {.inline.} = proc suggestSym*(n: PNode, s: PSym) {.inline.} =
## misnamed: should be 'symDeclared' ## misnamed: should be 'symDeclared'
if optUsages in gGlobalOptions: if optUsages in gGlobalOptions:
findUsages(n, s) findUsages(n, s)
if optDef in gGlobalOptions: if optDef in gGlobalOptions:
findDefinition(n, s) findDefinition(n, s)
if isServing:
addToSourceMap(s, n.info)
proc markUsed(n: PNode, s: PSym) = proc markUsed(n: PNode, s: PSym) =
incl(s.flags, sfUsed) incl(s.flags, sfUsed)

View file

@ -0,0 +1,7 @@
main.nim
> c
SuccessX
> idetools --trackDirty:main_dirty.nim,main.nim,12,7 --suggest main.nim
skField\tx
skField\ty

View file

@ -0,0 +1,10 @@
main.nim
> idetools --track:main.nim,5,18 --def main.nim
strutils.toUpper
SuccessX
> idetools --track:main.nim,5,18 --def main.nim
strutils.toUpper
SuccessX
> c
SuccessX

14
tests/caas/main_dirty.nim Normal file
View file

@ -0,0 +1,14 @@
import imported, strutils
type
TFoo = object
x: int
y: string
proc main =
var t1 = "text"
var t2 = t1.toUpper
var foo = TFoo(x: 10, y: "test")
foo.
echo(t1 +++ t2)

View file

@ -0,0 +1,7 @@
main.nim
> idetools --trackDirty:main_dirty.nim,main.nim,12,7 --suggest main.nim
skField\tx
skField\ty
> c
SuccessX