summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2015-01-26 21:38:39 +0100
committerAraq <rumpf_a@web.de>2015-01-27 01:36:19 +0100
commit26b853923cbbd92b9b74cf1b9dce773b0ff39cf3 (patch)
tree6ccfe4b728b2469b69fe4a884f393b51dc22ab26 /compiler
parent217390d18192e87534e61b9d15c55d44b7e163f7 (diff)
downloadNim-26b853923cbbd92b9b74cf1b9dce773b0ff39cf3.tar.gz
nimsuggest: first version
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/commands.nim20
-rw-r--r--compiler/idents.nim2
-rw-r--r--compiler/lexer.nim10
-rw-r--r--compiler/main.nim16
-rw-r--r--compiler/modules.nim13
-rw-r--r--compiler/msgs.nim67
-rw-r--r--compiler/nim.nim2
-rw-r--r--compiler/nimsuggest/nimsuggest.nim187
-rw-r--r--compiler/options.nim13
-rw-r--r--compiler/parser.nim17
-rw-r--r--compiler/passes.nim2
-rw-r--r--compiler/pragmas.nim6
-rw-r--r--compiler/semcall.nim3
-rw-r--r--compiler/semtypinst.nim1
-rw-r--r--compiler/service.nim16
-rw-r--r--compiler/suggest.nim197
-rw-r--r--compiler/vm.nim2
18 files changed, 361 insertions, 216 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 883b68d71..00515875f 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -428,6 +428,7 @@ type
     nfExplicitCall # x.y() was used instead of x.y
     nfExprCall  # this is an attempt to call a regular expression
     nfIsRef     # this node is a 'ref' node; used for the VM
+    nfIsCursor  # this node is attached a cursor; used for idetools
  
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 28)
@@ -883,7 +884,7 @@ const
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
   PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
                                       nfDotSetter, nfDotField,
-                                      nfIsRef}
+                                      nfIsRef, nfIsCursor}
   namePos* = 0
   patternPos* = 1    # empty except for term rewriting macros
   genericParamsPos* = 2
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 9fa221de0..a438ea566 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -65,14 +65,14 @@ proc getCommandLineDesc(): string =
 proc helpOnError(pass: TCmdLinePass) = 
   if pass == passCmd1:
     msgWriteln(getCommandLineDesc())
-    quit(0)
+    msgQuit(0)
 
 proc writeAdvancedUsage(pass: TCmdLinePass) = 
   if pass == passCmd1:
     msgWriteln(`%`(HelpMessage, [VersionAsString, 
                                  platform.OS[platform.hostOS].name, 
                                  CPU[platform.hostCPU].name]) & AdvancedUsage)
-    quit(0)
+    msgQuit(0)
 
 proc writeVersionInfo(pass: TCmdLinePass) = 
   if pass == passCmd1:
@@ -87,7 +87,7 @@ proc writeVersionInfo(pass: TCmdLinePass) =
     msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
       usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
       usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedNoGC)
-    quit(0)
+    msgQuit(0)
 
 var
   helpWritten: bool
@@ -255,8 +255,7 @@ proc trackDirty(arg: string, info: TLineInfo) =
   gDirtyBufferIdx = a[0].fileInfoIdx
   gDirtyOriginalIdx = a[1].fileInfoIdx
  
-  optTrackPos = newLineInfo(gDirtyBufferIdx, line, column)
-  msgs.addCheckpoint(optTrackPos)
+  gTrackPos = newLineInfo(gDirtyBufferIdx, line, column)
 
 proc track(arg: string, info: TLineInfo) = 
   var a = arg.split(',')
@@ -266,8 +265,7 @@ proc track(arg: string, info: TLineInfo) =
     localError(info, errInvalidNumber, a[1])
   if parseUtils.parseInt(a[2], column) <= 0:
     localError(info, errInvalidNumber, a[2])
-  optTrackPos = newLineInfo(a[0], line, column)
-  msgs.addCheckpoint(optTrackPos)
+  gTrackPos = newLineInfo(a[0], line, column)
 
 proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   if pass in {passCmd2, passPP}:
@@ -541,19 +539,19 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     trackDirty(arg, info)
   of "suggest": 
     expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optSuggest)
+    gIdeCmd = ideSug
   of "def":
     expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optDef)
+    gIdeCmd = ideDef
   of "eval":
     expectArg(switch, arg, pass, info)
     gEvalExpr = arg
   of "context":
     expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optContext)
+    gIdeCmd = ideCon
   of "usages":
     expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optUsages)
+    gIdeCmd = ideUse
   of "stdout":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optStdout)
diff --git a/compiler/idents.nim b/compiler/idents.nim
index 775bffa00..0cca18929 100644
--- a/compiler/idents.nim
+++ b/compiler/idents.nim
@@ -25,7 +25,7 @@ type
     next*: PIdent             # for hash-table chaining
     h*: THash                 # hash value of s
 
-var firstCharIsCS*: bool
+var firstCharIsCS*: bool = true
 var buckets*: array[0..4096 * 2 - 1, PIdent]
 
 proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index d856063cb..4fbac2d5c 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -693,7 +693,15 @@ proc scanComment(L: var TLexer, tok: var TToken) =
   when not defined(nimfix):
     assert buf[pos+1] == '#'
     if buf[pos+2] == '[':
-      lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['")
+      if buf[pos+3] == ']':
+        #  ##[] is the (rather complex) "cursor token" for idetools
+        tok.tokType = tkComment
+        tok.literal = "[]"
+        inc(L.bufpos, 4)
+        return
+      else:
+        lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['")
+    
   tok.tokType = tkComment
   # iNumber contains the number of '\n' in the token
   tok.iNumber = 0
diff --git a/compiler/main.nim b/compiler/main.nim
index 05209fa80..4cf9adc0d 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -58,12 +58,7 @@ proc commandCompileToC =
   registerPass(cgenPass)
   rodPass()
   #registerPass(cleanupPass())
-  if optCaasEnabled in gGlobalOptions:
-    # echo "BEFORE CHECK DEP"
-    # discard checkDepMem(gProjectMainIdx)
-    # echo "CHECK DEP COMPLETE"
-    discard
-
+  
   compileProject()
   cgenWriteModules()
   if gCmd != cmdRun:
@@ -177,17 +172,15 @@ proc commandSuggest =
     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()
     # XXX: this handles the case when the dirty buffer is the main file,
     # but doesn't handle the case when it's imported module
-    var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx
-                   else: gProjectMainIdx
-    compileProject(projFile)
+    #var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx
+    #               else: gProjectMainIdx
+    compileProject() #(projFile)
 
 proc resetMemory =
   resetCompilationLists()
@@ -218,7 +211,6 @@ proc resetMemory =
   # rodread.gMods
 
   # !! ropes.cache
-  # semthreads.computed?
   #
   # suggest.usageSym
   #
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 3dedc4d18..db05ccc6c 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -34,9 +34,6 @@ proc getModule(fileIdx: int32): PSym =
   if fileIdx >= 0 and fileIdx < gCompiledModules.len:
     result = gCompiledModules[fileIdx]
 
-template compiledAt(x: PSym): expr =
-  gMemCacheData[x.position].compiledAt
-
 template crc(x: PSym): expr =
   gMemCacheData[x.position].crc
 
@@ -74,10 +71,12 @@ proc addDep(x: PSym, dep: int32) =
 
 proc resetModule*(fileIdx: int32) =
   # echo "HARD RESETTING ", fileIdx.toFilename
-  gMemCacheData[fileIdx].needsRecompile = Yes
-  gCompiledModules[fileIdx] = nil
-  cgendata.gModules[fileIdx] = nil
-  resetSourceMap(fileIdx)
+  if fileIdx <% gMemCacheData.len:
+    gMemCacheData[fileIdx].needsRecompile = Yes
+  if fileIdx <% gCompiledModules.len:
+    gCompiledModules[fileIdx] = nil
+  if fileIdx <% cgendata.gModules.len:
+    cgendata.gModules[fileIdx] = nil
 
 proc resetAllModules* =
   for i in 0..gCompiledModules.high:
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index d94b8ade8..e19e6f618 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -10,9 +10,6 @@
 import
   options, strutils, os, tables, ropes, platform
 
-when useCaas:
-  import sockets
-
 type 
   TMsgKind* = enum 
     errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated, 
@@ -572,9 +569,6 @@ var
   gWarnCounter*: int = 0
   gErrorMax*: int = 1         # stop after gErrorMax errors
 
-when useCaas:
-  var stdoutSocket*: Socket
-
 proc unknownLineInfo*(): TLineInfo =
   result.line = int16(-1)
   result.col = int16(-1)
@@ -586,32 +580,35 @@ var
   bufferedMsgs*: seq[string]
 
   errorOutputs* = {eStdOut, eStdErr}
+  writelnHook*: proc (output: string) {.closure.}
 
 proc clearBufferedMsgs* =
   bufferedMsgs = nil
 
 proc suggestWriteln*(s: string) =
   if eStdOut in errorOutputs:
-    when useCaas:
-      if isNil(stdoutSocket): writeln(stdout, s)
-      else:
-        writeln(stdout, s)
-        stdoutSocket.send(s & "\c\L")
-    else:
-      writeln(stdout, s)
+    if isNil(writelnHook): writeln(stdout, s)
+    else: writelnHook(s)
   
   if eInMemory in errorOutputs:
     bufferedMsgs.safeAdd(s)
 
+proc msgQuit*(x: int8) = quit x
+proc msgQuit*(x: string) = quit x
+
 proc suggestQuit*() =
-  if not isServing:
-    quit(0)
-  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.
+  when true:
     raise newException(ESuggestDone, "suggest done")
+  else:
+    if not isServing:
+      assert false
+      quit(0)
+    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")
 
 # this format is understood by many text editors: it is the same that
 # Borland and Freepascal use
@@ -679,14 +676,7 @@ proc `??`* (info: TLineInfo, filename: string): bool =
   # only for debugging purposes
   result = filename in info.toFilename
 
-var checkPoints*: seq[TLineInfo] = @[]
-var optTrackPos*: TLineInfo
-
-proc addCheckpoint*(info: TLineInfo) = 
-  checkPoints.add(info)
-
-proc addCheckpoint*(filename: string, line: int) = 
-  addCheckpoint(newLineInfo(filename, line, - 1))
+var gTrackPos*: TLineInfo
 
 proc outWriteln*(s: string) = 
   ## Writes to stdout. Always.
@@ -694,7 +684,8 @@ proc outWriteln*(s: string) =
  
 proc msgWriteln*(s: string) = 
   ## Writes to stdout. If --stdout option is given, writes to stderr instead.
-  if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
+
+  #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
 
   if optStdout in gGlobalOptions:
     if eStdErr in errorOutputs: writeln(stderr, s)
@@ -715,19 +706,6 @@ proc getMessageStr(msg: TMsgKind, arg: string): string =
   result = msgKindToString(msg) % [arg]
 
 type
-  TCheckPointResult* = enum 
-    cpNone, cpFuzzy, cpExact
-
-proc inCheckpoint*(current: TLineInfo): TCheckPointResult = 
-  for i in countup(0, high(checkPoints)): 
-    if current.fileIndex == checkPoints[i].fileIndex:
-      if current.line == checkPoints[i].line and
-          abs(current.col-checkPoints[i].col) < 4:
-        return cpExact
-      if current.line >= checkPoints[i].line:
-        return cpFuzzy
-
-type
   TErrorHandling = enum doNothing, doAbort, doRaise
 
 proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
@@ -798,6 +776,9 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
   result = frmt % [toMsgFilename(info), coordToStr(info.line),
                    coordToStr(info.col), getMessageStr(msg, arg)]
 
+proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
+  msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
+
 proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, 
                eh: TErrorHandling) =
   var frmt: string
@@ -821,7 +802,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
     inc(gHintCounter)
   let s = frmt % [toMsgFilename(info), coordToStr(info.line),
                   coordToStr(info.col), getMessageStr(msg, arg)]
-  if not ignoreMsg:
+  if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg):
     msgWriteln(s)
     if optPrintSurroundingSrc and msg in errMin..errMax:
       info.writeSurroundingSrc
diff --git a/compiler/nim.nim b/compiler/nim.nim
index a87e0a1ac..b23d438e0 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -89,4 +89,4 @@ condsyms.initDefines()
 
 when not defined(selftest):
   handleCmdLine()
-  quit(int8(msgs.gErrorCounter > 0))
+  msgQuit(int8(msgs.gErrorCounter > 0))
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim
new file mode 100644
index 000000000..b9d167beb
--- /dev/null
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -0,0 +1,187 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Nimsuggest is a tool that helps to give editors IDE like capabilities.
+
+import strutils, os, parseopt, parseUtils
+import options, commands, modules, sem, passes, passaux, msgs, nimconf,
+  extccomp, condsyms, lists, net, rdstdin
+
+const Usage = """
+Nimsuggest - Tool to give every editor IDE like capabilities for Nim
+Usage:
+  nimsuggest [options] projectfile.nim
+
+Options:
+  --port:PORT             port, by default 6000
+  --address:HOST          binds to that address, by default ""
+  --stdin                 read commands from stdin and write results to
+                          stdout instead of using sockets
+
+The server then listens to the connection and takes line-based commands.
+
+In addition, all command line options of Nim that do not affect code generation
+are supported.
+"""
+
+var
+  gPort = 6000.Port
+  gAddress = ""
+  gUseStdin: bool
+
+const
+  seps = {':', ';', ' ', '\t'}
+  Help = "usage: sug|con|def|use dirtybuffer.nim[;originalfile.nim]:line:col\n"&
+         "type 'quit' to quit\n" &
+         "type 'debug' to toggle debug mode on/off\n" &
+         "type 'terse' to toggle terse mode on/off"
+
+proc parseQuoted(cmd: string; outp: var string; start: int): int =
+  var i = start
+  i += skipWhitespace(cmd, i)
+  if cmd[i] == '"':
+    i += parseUntil(cmd, outp, '"', i+1)+1
+  else:
+    i += parseUntil(cmd, outp, seps, i)
+  result = i
+
+proc action(cmd: string) =
+  template toggle(sw) =
+    if sw in gGlobalOptions:
+      excl(gGlobalOptions, sw)
+    else:
+      incl(gGlobalOptions, sw)
+    return
+
+  var opc = ""
+  var i = parseIdent(cmd, opc, 0)
+  case opc.normalize
+  of "sug": gIdeCmd = ideSug
+  of "con": gIdeCmd = ideCon
+  of "def": gIdeCmd = ideDef
+  of "use":
+    modules.resetAllModules()
+    gIdeCmd = ideUse
+  of "quit": quit()
+  of "debug": toggle optIdeDebug
+  of "terse": toggle optIdeTerse
+  else:
+    echo Help
+    return
+  var dirtyfile = ""
+  var orig = ""
+  i = parseQuoted(cmd, dirtyfile, i)
+  if cmd[i] == ';':
+    i = parseQuoted(cmd, orig, i+1)
+  i += skipWhile(cmd, seps, i)
+  var line, col = -1
+  i += parseInt(cmd, line, i)
+  i += skipWhile(cmd, seps, i)
+  i += parseInt(cmd, col, i)
+  if dirtyfile.len != 0:
+    gDirtyBufferIdx = dirtyfile.fileInfoIdx
+    gDirtyOriginalIdx = if orig.len != 0: orig.fileInfoIdx else: gDirtyBufferIdx
+  else:
+    discard "use the same filename as in the last command"
+  resetModule gDirtyBufferIdx
+  if gDirtyBufferIdx != gProjectMainIdx:
+    resetModule gProjectMainIdx
+  gTrackPos = newLineInfo(gDirtyBufferIdx, line, col)
+  #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx
+  gErrorCounter = 0
+  compileProject()
+
+proc serve() =
+  gDirtyBufferIdx = gProjectMainIdx
+  gDirtyOriginalIdx = gProjectMainIdx
+  # do not stop after the first error:
+  msgs.gErrorMax = high(int)
+  if gUseStdin:
+    echo Help
+    var line = ""
+    while readLineFromStdin("> ", line):
+      action line
+      echo ""
+      flushFile(stdout)
+  else:
+    var server = newSocket()
+    server.bindAddr(gPort, gAddress)
+    var inp = "".TaintedString
+    server.listen()
+    var stdoutSocket = newSocket()
+    msgs.writelnHook = proc (line: string) =
+      stdoutSocket.send(line & "\c\L")
+    while true:
+      accept(server, stdoutSocket)
+      stdoutSocket.readLine(inp)
+      action inp.string
+      stdoutSocket.send("\c\L")
+      stdoutSocket.close()
+
+proc mainCommand =
+  registerPass verbosePass
+  registerPass semPass
+  gCmd = cmdIdeTools
+  incl gGlobalOptions, optCaasEnabled
+  isServing = true
+  wantMainModule()
+  appendStr(searchPaths, options.libpath)
+  if gProjectFull.len != 0:
+    # current path is always looked first for modules
+    prependStr(searchPaths, gProjectPath)
+
+  serve()
+
+proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
+  var p = parseopt.initOptParser(cmd)
+  while true: 
+    parseopt.next(p)
+    case p.kind
+    of cmdEnd: break 
+    of cmdLongoption, cmdShortOption: 
+      case p.key.normalize
+      of "port": gPort = parseInt(p.val).Port
+      of "address": gAddress = p.val
+      of "stdin": gUseStdin = true
+      else: processSwitch(pass, p)
+    of cmdArgument:
+      options.gProjectName = unixToNativePath(p.key)
+      # if processArgument(pass, p, argsCount): break
+
+proc handleCmdLine() =
+  if paramCount() == 0:
+    stdout.writeln(Usage)
+  else:
+    processCmdLine(passCmd1, "")
+    if gProjectName != "":
+      try:
+        gProjectFull = canonicalizePath(gProjectName)
+      except OSError:
+        gProjectFull = gProjectName
+      var p = splitFile(gProjectFull)
+      gProjectPath = p.dir
+      gProjectName = p.name
+    else:
+      gProjectPath = getCurrentDir()
+    loadConfigs(DefaultConfig) # load all config files
+    # now process command line arguments again, because some options in the
+    # command line can overwite the config file's settings
+    extccomp.initVars()
+    processCmdLine(passCmd2, "")
+    mainCommand()
+
+when false:
+  proc quitCalled() {.noconv.} =
+    writeStackTrace()
+
+  addQuitProc(quitCalled)
+
+condsyms.initDefines()
+defineSymbol "nimsuggest"
+handleCmdline()
diff --git a/compiler/options.nim b/compiler/options.nim
index 415ac8430..0a1fbebc1 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -56,17 +56,14 @@ type                          # please make sure we have under 32 options
     optNoMain,                # do not generate a "main" proc
     optThreads,               # support for multi-threading
     optStdout,                # output to stdout
-    optSuggest,               # ideTools: 'suggest'
-    optContext,               # ideTools: 'context'
-    optDef,                   # ideTools: 'def'
-    optUsages,                # ideTools: 'usages'
     optThreadAnalysis,        # thread analysis pass
     optTaintMode,             # taint mode turned on
     optTlsEmulation,          # thread var emulation turned on
     optGenIndex               # generate index file for documentation;
     optEmbedOrigSrc           # embed the original source in the generated code
                               # also: generate header file
-   
+    optIdeDebug               # idetools: debug mode
+    optIdeTerse               # idetools: use terse descriptions
   TGlobalOptions* = set[TGlobalOption]
   TCommands* = enum           # Nim's commands
                               # **keep binary compatible**
@@ -86,6 +83,12 @@ type                          # please make sure we have under 32 options
   TGCMode* = enum             # the selected GC
     gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
 
+  TIdeCmd* = enum
+    ideNone, ideSug, ideCon, ideDef, ideUse
+
+var
+  gIdeCmd*: TIdeCmd
+
 const
   ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck, 
     optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck}
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 76285b7ec..adf3b72a3 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -111,7 +111,12 @@ proc rawSkipComment(p: var TParser, node: PNode) =
   if p.tok.tokType == tkComment:
     if node != nil:
       if node.comment == nil: node.comment = ""
-      add(node.comment, p.tok.literal)
+      if p.tok.literal == "[]":
+        node.flags.incl nfIsCursor
+        #echo "parser: "
+        #debug node
+      else:
+        add(node.comment, p.tok.literal)
     else:
       parMessage(p, errInternal, "skipComment")
     getTok(p)
@@ -379,7 +384,8 @@ proc dotExpr(p: var TParser, a: PNode): PNode =
   #| dotExpr = expr '.' optInd ('type' | 'addr' | symbol)
   var info = p.parLineInfo
   getTok(p)
-  optInd(p, a)
+  result = newNodeI(nkDotExpr, info)
+  optInd(p, result)
   case p.tok.tokType
   of tkType:
     result = newNodeP(nkTypeOfExpr, p)
@@ -390,7 +396,6 @@ proc dotExpr(p: var TParser, a: PNode): PNode =
     getTok(p)
     addSon(result, a)
   else:
-    result = newNodeI(nkDotExpr, info)
     addSon(result, a)
     addSon(result, parseSymbol(p))
 
@@ -737,7 +742,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
     var a = newNodeP(nkInfix, p)
     var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
     getTok(p)
-    optInd(p, opNode)
+    optInd(p, a)
     # read sub-expression with higher priority:
     var b = simpleExprAux(p, opPrec + leftAssoc, modeB)
     addSon(a, opNode)
@@ -1735,8 +1740,8 @@ proc parseObject(p: var TParser): PNode =
 
 proc parseTypeClassParam(p: var TParser): PNode =
   if p.tok.tokType == tkVar:
+    result = newNodeP(nkVarTy, p)
     getTok(p)
-    result = newNode(nkVarTy)
     result.addSon(p.parseSymbol)
   else:
     result = p.parseSymbol
@@ -1747,7 +1752,7 @@ proc parseTypeClass(p: var TParser): PNode =
   #|               &IND{>} stmt
   result = newNodeP(nkTypeClassTy, p)
   getTok(p)
-  var args = newNode(nkArgList)
+  var args = newNodeP(nkArgList, p)
   addSon(result, args)
   addSon(args, p.parseTypeClassParam)
   while p.tok.tokType == tkComma:
diff --git a/compiler/passes.nim b/compiler/passes.nim
index a63e29b35..95c944410 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -174,7 +174,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
       if s == nil: 
         rawMessage(errCannotOpenFile, filename)
         return
-    else: 
+    else:
       s = stream
     while true: 
       openParsers(p, fileIdx, s)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 1b04d5296..735460906 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -411,12 +411,6 @@ proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
 proc pragmaBreakpoint(c: PContext, n: PNode) = 
   discard getOptionalStr(c, n, "")
 
-proc pragmaCheckpoint(c: PContext, n: PNode) = 
-  # checkpoints can be used to debug the compiler; they are not documented
-  var info = n.info
-  inc(info.line)              # next line is affected!
-  msgs.addCheckpoint(info)
-
 proc pragmaWatchpoint(c: PContext, n: PNode) =
   if n.kind == nkExprColonExpr:
     n.sons[1] = c.semExpr(c, n.sons[1])
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 7f7005633..cdfdfc9d0 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -84,8 +84,9 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   if c.inCompilesContext > 0: 
     # fail fast:
     globalError(n.info, errTypeMismatch, "")
-  if errors.len == 0:
+  if errors.isNil or errors.len == 0:
     localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
+    return
 
   # to avoid confusing errors like: 
   #   got (SslPtr, SocketHandle)
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index d8efdbb23..7b8f478ec 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -101,7 +101,6 @@ template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
       echo "UNEXPECTED META ", t.id, " ", instantiationInfo(-1)
       debug t
       writeStackTrace()
-      quit 1
 
 proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
   result = replaceTypeVarsTAux(cl, t)
diff --git a/compiler/service.nim b/compiler/service.nim
index 4a1b296cd..d84fdf060 100644
--- a/compiler/service.nim
+++ b/compiler/service.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -14,7 +14,7 @@ import
   extccomp, strutils, os, platform, parseopt
 
 when useCaas:
-  import sockets
+  import net
 
 # We cache modules and the dependency graph. However, we don't check for
 # file changes but expect the client to tell us about them, otherwise the
@@ -61,14 +61,16 @@ proc serve*(action: proc (){.nimcall.}) =
 
   of "tcp", "":
     when useCaas:
-      var server = socket()
-      if server == invalidSocket: raiseOSError(osLastError())
+      var server = newSocket()
       let p = getConfigVar("server.port")
       let port = if p.len > 0: parseInt(p).Port else: 6000.Port
       server.bindAddr(port, getConfigVar("server.address"))
       var inp = "".TaintedString
       server.listen()
-      new(stdoutSocket)
+      var stdoutSocket = newSocket()
+      msgs.writelnHook = proc (line: string) =
+        stdoutSocket.send(line & "\c\L")
+
       while true:
         accept(server, stdoutSocket)
         stdoutSocket.readLine(inp)
@@ -76,7 +78,7 @@ proc serve*(action: proc (){.nimcall.}) =
         stdoutSocket.send("\c\L")
         stdoutSocket.close()
     else:
-      quit "server.type not supported; compiler built without caas support"
+      msgQuit "server.type not supported; compiler built without caas support"
   else:
     echo "Invalid server.type:", typ
-    quit 1
+    msgQuit 1
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index f7b00c8f8..bd8341936 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -31,35 +31,52 @@ proc origModuleName(m: PSym): string =
 proc symToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string = 
   result = section
   result.add(sep)
-  result.add($s.kind)
-  result.add(sep)
-  if not isLocal and s.kind != skModule:
-    let ow = s.owner
-    if ow.kind != skModule and ow.owner != nil:
-      let ow2 = ow.owner
-      result.add(ow2.origModuleName)
+  if optIdeTerse in gGlobalOptions:
+    if s.kind in routineKinds:
+      result.add renderTree(s.ast, {renderNoBody, renderNoComments,
+                                    renderDocComments, renderNoPragmas})
+    else:
+      result.add s.name.s
+    result.add(sep)
+    result.add(toFullPath(li))
+    result.add(sep)
+    result.add($toLinenumber(li))
+    result.add(sep)
+    result.add($toColumn(li))
+  else:
+    result.add($s.kind)
+    result.add(sep)
+    if not isLocal and s.kind != skModule:
+      let ow = s.owner
+      if ow.kind != skModule and ow.owner != nil:
+        let ow2 = ow.owner
+        result.add(ow2.origModuleName)
+        result.add('.')
+      result.add(ow.origModuleName)
       result.add('.')
-    result.add(ow.origModuleName)
-    result.add('.')
-  result.add(s.name.s)
-  result.add(sep)
-  if s.typ != nil: 
-    result.add(typeToString(s.typ))
-  result.add(sep)
-  result.add(toFullPath(li))
-  result.add(sep)
-  result.add($toLinenumber(li))
-  result.add(sep)
-  result.add($toColumn(li))
-  result.add(sep)
-  when not defined(noDocgen):
-    result.add(s.extractDocComment.escape)
+    result.add(s.name.s)
+    result.add(sep)
+    if s.typ != nil: 
+      result.add(typeToString(s.typ))
+    result.add(sep)
+    result.add(toFullPath(li))
+    result.add(sep)
+    result.add($toLinenumber(li))
+    result.add(sep)
+    result.add($toColumn(li))
+    result.add(sep)
+    when not defined(noDocgen):
+      result.add(s.extractDocComment.escape)
 
 proc symToStr(s: PSym, isLocal: bool, section: string): string = 
   result = symToStr(s, isLocal, section, s.info)
 
 proc filterSym(s: PSym): bool {.inline.} =
-  result = s.name.s[0] in lexer.SymChars and s.kind != skModule
+  result = s.kind != skModule
+
+proc filterSymNoOpr(s: PSym): bool {.inline.} =
+  result = s.kind != skModule and s.name.s[0] in lexer.SymChars and
+     not isKeyword(s.name)
 
 proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
   let fmoduleId = getModule(f).id
@@ -131,11 +148,20 @@ proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var int) =
 
 proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = 
   if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil:
+    # special rule: if system and some weird generic match via 'tyExpr'
+    # or 'tyGenericParam' we won't list it either to reduce the noise (nobody
+    # wants 'system.`-|` as suggestion
+    let m = s.getModule()
+    if m != nil and sfSystemModule in m.flags:
+      if s.kind == skType: return
+      var exp = s.typ.sons[1].skipTypes({tyGenericInst, tyVar})
+      if exp.kind == tyVarargs: exp = elemType(exp)
+      if exp.kind in {tyExpr, tyStmt, tyGenericParam, tyAnything}: return
     result = sigmatch.argtypeMatches(c, s.typ.sons[1], firstArg)
 
 proc suggestOperations(c: PContext, n: PNode, typ: PType, outputs: var int) =
   assert typ != nil
-  wholeSymTab(filterSym(it) and typeFits(c, it, typ), sectionSuggest)
+  wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), sectionSuggest)
 
 proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
   # do not produce too many symbols:
@@ -191,19 +217,28 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
     else:
       suggestOperations(c, n, typ, outputs)
 
+type
+  TCheckPointResult = enum 
+    cpNone, cpFuzzy, cpExact
+
+proc inCheckpoint(current: TLineInfo): TCheckPointResult = 
+  if current.fileIndex == gTrackPos.fileIndex:
+    if current.line == gTrackPos.line and
+        abs(current.col-gTrackPos.col) < 4:
+      return cpExact
+    if current.line >= gTrackPos.line:
+      return cpFuzzy
+
 proc findClosestDot(n: PNode): PNode =
-  if n.kind == nkDotExpr and msgs.inCheckpoint(n.info) == cpExact:
+  if n.kind == nkDotExpr and inCheckpoint(n.info) == cpExact:
     result = n
   else:
     for i in 0.. <safeLen(n):
       result = findClosestDot(n.sons[i])
       if result != nil: return
 
-const
-  CallNodes = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit}
-
 proc findClosestCall(n: PNode): PNode = 
-  if n.kind in CallNodes and msgs.inCheckpoint(n.info) == cpExact: 
+  if n.kind in nkCallKinds and inCheckpoint(n.info) == cpExact: 
     result = n
   else:
     for i in 0.. <safeLen(n):
@@ -211,15 +246,14 @@ proc findClosestCall(n: PNode): PNode =
       if result != nil: return
 
 proc isTracked(current: TLineInfo, tokenLen: int): bool =
-  for i in countup(0, high(checkPoints)):
-    if current.fileIndex == checkPoints[i].fileIndex:
-      if current.line == checkPoints[i].line:
-        let col = checkPoints[i].col
-        if col >= current.col and col <= current.col+tokenLen-1:
-          return true
+  if current.fileIndex == gTrackPos.fileIndex:
+    if current.line == gTrackPos.line:
+      let col = gTrackPos.col
+      if col >= current.col and col <= current.col+tokenLen-1:
+        return true
 
 proc findClosestSym(n: PNode): PNode = 
-  if n.kind == nkSym and msgs.inCheckpoint(n.info) == cpExact: 
+  if n.kind == nkSym and inCheckpoint(n.info) == cpExact: 
     result = n
   elif n.kind notin {nkNone..nkNilLit}:
     for i in 0.. <sonsLen(n):
@@ -258,69 +292,18 @@ proc findDefinition(info: TLineInfo; s: PSym) =
     suggestWriteln(symToStr(s, isLocal=false, sectionDef))
     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*(info: TLineInfo; s: PSym) {.inline.} =
   ## misnamed: should be 'symDeclared'
-  if optUsages in gGlobalOptions:
+  if gIdeCmd == ideUse:
     findUsages(info, s)
-  if optDef in gGlobalOptions:
+  elif gIdeCmd == ideDef:
     findDefinition(info, s)
-  if isServing:
-    addToSourceMap(s, info)
 
 proc markUsed(info: TLineInfo; s: PSym) =
   incl(s.flags, sfUsed)
@@ -334,30 +317,28 @@ proc useSym*(sym: PSym): PNode =
   markUsed(result.info, sym)
 
 proc suggestExpr*(c: PContext, node: PNode) = 
-  var cp = msgs.inCheckpoint(node.info)
-  if cp == cpNone: return
+  if nfIsCursor notin node.flags:
+    if gTrackPos.line < 0: return
+    var cp = inCheckpoint(node.info)
+    if cp == cpNone: return
   var outputs = 0
   # This keeps semExpr() from coming here recursively:
   if c.inCompilesContext > 0: return
   inc(c.inCompilesContext)
-  
-  if optSuggest in gGlobalOptions:
-    var n = findClosestDot(node)
+
+  if gIdeCmd == ideSug:
+    var n = if nfIsCursor in node.flags: node else: findClosestDot(node)
     if n == nil: n = node
-    else: cp = cpExact
-    if n.kind == nkDotExpr and cp == cpExact:
+    if n.kind == nkDotExpr:
       var obj = safeSemExpr(c, n.sons[0])
       suggestFieldAccess(c, obj, outputs)
     else:
-      #debug n
       suggestEverything(c, n, outputs)
   
-  if optContext in gGlobalOptions:
-    var n = findClosestCall(node)
+  elif gIdeCmd == ideCon:
+    var n = if nfIsCursor in node.flags: node else: findClosestCall(node)
     if n == nil: n = node
-    else: cp = cpExact
-    
-    if n.kind in CallNodes:
+    if n.kind in nkCallKinds:
       var a = copyNode(n)
       var x = safeSemExpr(c, n.sons[0])
       if x.kind == nkEmpty or x.typ == nil: x = n.sons[0]
@@ -368,15 +349,9 @@ proc suggestExpr*(c: PContext, node: PNode) =
         if x.kind == nkEmpty or x.typ == nil: break
         addSon(a, x)
       suggestCall(c, a, n, outputs)
-  
+          
   dec(c.inCompilesContext)
-  if outputs > 0 and optUsages notin gGlobalOptions: suggestQuit()
+  if outputs > 0 and gIdeCmd != ideUse: suggestQuit()
 
 proc suggestStmt*(c: PContext, n: PNode) = 
   suggestExpr(c, n)
-
-proc findSuggest*(c: PContext, n: PNode) = 
-  if n == nil: return
-  suggestExpr(c, n)
-  for i in 0.. <safeLen(n):
-    findSuggest(c, n.sons[i])
diff --git a/compiler/vm.nim b/compiler/vm.nim
index ae5fcb43f..7edbb3fd2 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1012,7 +1012,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcQuit:
       if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
         message(c.debug[pc], hintQuitCalled)
-        quit(int(getOrdValue(regs[ra].regToNode)))
+        msgQuit(int8(getOrdValue(regs[ra].regToNode)))
       else:
         return TFullReg(kind: rkNone)
     of opcSetLenStr: