summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/cgen.nim8
-rwxr-xr-xcompiler/commands.nim3
-rwxr-xr-xcompiler/depends.nim7
-rw-r--r--compiler/docgen2.nim6
-rwxr-xr-xcompiler/ecmasgen.nim8
-rwxr-xr-xcompiler/evals.nim6
-rwxr-xr-xcompiler/main.nim97
-rwxr-xr-xcompiler/nimconf.nim19
-rwxr-xr-xcompiler/nimrod.cfg13
-rwxr-xr-xcompiler/options.nim2
-rwxr-xr-xcompiler/passaux.nim11
-rwxr-xr-xcompiler/passes.nim58
-rwxr-xr-xcompiler/rodwrite.nim8
-rwxr-xr-xcompiler/sem.nim9
-rw-r--r--compiler/service.nim41
-rwxr-xr-xcompiler/transf.nim8
-rwxr-xr-xdoc/advopt.txt1
-rwxr-xr-xlib/pure/streams.nim8
18 files changed, 176 insertions, 137 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 5bdbefde1..cf6af671e 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -19,7 +19,6 @@ import
 when options.hasTinyCBackend:
   import tccgen
 
-proc cgenPass*(): TPass
 # implementation
 
 var
@@ -1157,10 +1156,5 @@ proc myClose(b: PPassContext, n: PNode): PNode =
     writeMapping(gMapping)
     if generatedHeader != nil: writeHeader(generatedHeader)
 
-proc cgenPass(): TPass = 
-  initPass(result)
-  result.open = myOpen
-  result.openCached = myOpenCached
-  result.process = myProcess
-  result.close = myClose
+const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
 
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 50b4a1e6f..979da3db8 100755
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -458,6 +458,9 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
   of "def":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optDef)
+  of "eval":
+    expectArg(switch, arg, pass, info)
+    gEvalExpr = arg
   of "context":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optContext)
diff --git a/compiler/depends.nim b/compiler/depends.nim
index 4fde24ab4..f050c0993 100755
--- a/compiler/depends.nim
+++ b/compiler/depends.nim
@@ -12,7 +12,6 @@
 import 
   os, options, ast, astalgo, msgs, ropes, idents, passes, importer
 
-proc genDependPass*(): TPass
 proc generateDot*(project: string)
 
 type 
@@ -55,7 +54,5 @@ proc myOpen(module: PSym, filename: string): PPassContext =
   g.filename = filename
   result = g
 
-proc gendependPass(): TPass = 
-  initPass(result)
-  result.open = myOpen
-  result.process = addDotDependency
+const gendependPass* = makePass(open = myOpen, process = addDotDependency)
+
diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim
index 2d175adbf..6fa179e0f 100644
--- a/compiler/docgen2.nim
+++ b/compiler/docgen2.nim
@@ -45,11 +45,7 @@ proc myOpen(module: PSym, filename: string): PPassContext =
   g.doc = d
   result = g
 
-proc docgen2Pass*(): TPass = 
-  initPass(result)
-  result.open = myOpen
-  result.process = processNode
-  result.close = close
+const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
 
 proc finishDoc2Pass*(project: string) = 
   nil
diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim
index cff4cc1dd..d341a93be 100755
--- a/compiler/ecmasgen.nim
+++ b/compiler/ecmasgen.nim
@@ -17,7 +17,6 @@ import
   times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
   intsets, cgmeth
 
-proc ecmasgenPass*(): TPass
 # implementation
 
 type 
@@ -1620,9 +1619,4 @@ proc myOpenCached(s: PSym, filename: string, rd: PRodReader): PPassContext =
 proc myOpen(s: PSym, filename: string): PPassContext = 
   result = newModule(s, filename)
 
-proc ecmasgenPass(): TPass = 
-  InitPass(result)
-  result.open = myOpen
-  result.close = myClose
-  result.openCached = myOpenCached
-  result.process = myProcess
+const ecmasgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 20d354aaf..f503922c2 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -1440,9 +1440,5 @@ proc myOpen(module: PSym, filename: string): PPassContext =
 proc myProcess(c: PPassContext, n: PNode): PNode = 
   result = eval(PEvalContext(c), n)
 
-proc evalPass*(): TPass = 
-  initPass(result)
-  result.open = myOpen
-  result.close = myProcess
-  result.process = myProcess
+const evalPass* = makePass(myOpen, nil, myProcess, myProcess)
 
diff --git a/compiler/main.nim b/compiler/main.nim
index dabd5309b..448efbd1d 100755
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -16,7 +16,7 @@ import
   wordrecg, sem, semdata, idents, passes, docgen, extccomp,
   cgen, ecmasgen,
   platform, nimconf, importer, passaux, depends, evals, types, idgen,
-  tables, docgen2, service
+  tables, docgen2, service, magicsys, parser
 
 const
   has_LLVM_Backend = false
@@ -89,22 +89,30 @@ proc `==^`(a, b: string): bool =
   except EOS:
     result = false
 
+proc compileSystemModule =
+  if magicsys.SystemModule == nil:
+    discard CompileModule(options.libpath /"system", {sfSystemModule})
+
 proc CompileProject(projectFile = gProjectFull) =
   let systemFile = options.libpath / "system"
   if projectFile.addFileExt(nimExt) ==^ systemFile.addFileExt(nimExt):
     discard CompileModule(projectFile, {sfMainModule, sfSystemModule})
   else:
-    discard CompileModule(systemFile, {sfSystemModule})
+    compileSystemModule()
     discard CompileModule(projectFile, {sfMainModule})
 
+proc rodPass =
+  if optSymbolFiles in gGlobalOptions:
+    registerPass(rodwritePass)
+
 proc semanticPasses =
-  registerPass(verbosePass())
-  registerPass(sem.semPass())
+  registerPass verbosePass
+  registerPass semPass
 
 proc CommandGenDepend =
   semanticPasses()
-  registerPass(genDependPass())
-  registerPass(cleanupPass())
+  registerPass(genDependPass)
+  registerPass(cleanupPass)
   compileProject()
   generateDot(gProjectFull)
   execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
@@ -113,21 +121,21 @@ proc CommandGenDepend =
 proc CommandCheck =
   msgs.gErrorMax = high(int)  # do not stop after first error
   semanticPasses()            # use an empty backend for semantic checking only
-  registerPass(rodwrite.rodwritePass())
+  rodPass()
   compileProject(mainCommandArg())
 
 proc CommandDoc2 =
   msgs.gErrorMax = high(int)  # do not stop after first error
   semanticPasses()
-  registerPass(docgen2Pass())
+  registerPass(docgen2Pass)
   #registerPass(cleanupPass())
   compileProject(mainCommandArg())
   finishDoc2Pass(gProjectFull)
 
 proc CommandCompileToC =
   semanticPasses()
-  registerPass(cgen.cgenPass())
-  registerPass(rodwrite.rodwritePass())
+  registerPass(cgenPass)
+  rodPass()
   #registerPass(cleanupPass())
   compileProject()
   if gCmd != cmdRun:
@@ -137,7 +145,7 @@ when has_LLVM_Backend:
   proc CommandCompileToLLVM =
     semanticPasses()
     registerPass(llvmgen.llvmgenPass())
-    registerPass(rodwrite.rodwritePass())
+    rodPass()
     #registerPass(cleanupPass())
     compileProject()
 
@@ -148,27 +156,50 @@ proc CommandCompileToEcmaScript =
   DefineSymbol("nimrod") # 'nimrod' is always defined
   DefineSymbol("ecmascript")
   semanticPasses()
-  registerPass(ecmasgenPass())
+  registerPass(ecmasgenPass)
   compileProject()
 
-proc CommandInteractive =
-  msgs.gErrorMax = high(int)  # do not stop after first error
+proc InteractivePasses =
   incl(gGlobalOptions, optSafeCode)
   #setTarget(osNimrodVM, cpuNimrodVM)
   initDefines()
   DefineSymbol("nimrodvm")
-  registerPass(verbosePass())
-  registerPass(sem.semPass())
-  registerPass(evals.evalPass()) # load system module:
-  discard CompileModule(options.libpath /"system", {sfSystemModule})
+  registerPass(verbosePass)
+  registerPass(semPass)
+  registerPass(evalPass)
+
+var stdinModule: PSym
+proc makeStdinModule: PSym =
+  if stdinModule == nil:
+    stdinModule = newModule("stdin")
+    stdinModule.id = getID()
+  result = stdinModule
+
+proc CommandInteractive =
+  msgs.gErrorMax = high(int)  # do not stop after first error
+  InteractivePasses()
+  compileSystemModule()
   if commandArgs.len > 0:
     discard CompileModule(mainCommandArg(), {})
   else:
-    var m = newModule("stdin")
-    m.id = getID()
+    var m = makeStdinModule()
     incl(m.flags, sfMainModule)
     processModule(m, "stdin", LLStreamOpenStdIn(), nil)
 
+const evalPasses = [verbosePass, semPass, evalPass]
+
+proc evalNim(nodes: PNode, module: PSym, filename: string) =
+  # we don't want to mess with gPasses here, because in nimrod serve
+  # scenario, it may be set up properly for normal cgenPass() compilation
+  carryPasses(nodes, module, filename, evalPasses)
+
+proc commandEval(exp: string) =
+  if SystemModule == nil:
+    InteractivePasses()
+    compileSystemModule()
+  var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
+  evalNim(echoExp.parseString, makeStdinModule(), "stdin")
+
 proc CommandPretty =
   var module = parseFile(addFileExt(mainCommandArg(), NimExt))
   if module != nil: 
@@ -194,7 +225,7 @@ proc CommandScan =
 proc CommandSuggest =
   msgs.gErrorMax = high(int)  # do not stop after first error
   semanticPasses()
-  registerPass(rodwrite.rodwritePass())
+  rodPass()
   compileProject()
 
 proc wantMainModule =
@@ -202,6 +233,8 @@ proc wantMainModule =
     Fatal(gCmdLineInfo, errCommandExpectsFilename)
   
 proc MainCommand =
+  # In "nimrod serve" scenario, each command must reset the registered passes
+  clearPasses()
   appendStr(searchPaths, options.libpath)
   if gProjectFull.len != 0:
     # current path is always looked first for modules
@@ -299,20 +332,20 @@ proc MainCommand =
   of "i": 
     gCmd = cmdInteractive
     CommandInteractive()
+  of "e":
+    # XXX: temporary command for easier testing
+    commandEval(mainCommandArg())
   of "idetools":
     gCmd = cmdIdeTools
-    wantMainModule()
-    CommandSuggest()
+    if gEvalExpr != "":
+      commandEval(gEvalExpr)
+    else:
+      wantMainModule()
+      CommandSuggest()
   of "serve":
     gCmd = cmdIdeTools
-    msgs.gErrorMax = high(int)  # do not stop after first error
-    semanticPasses()
-    # no need to write rod files and would slow down things:
-    #registerPass(rodwrite.rodwritePass())
-    discard CompileModule(options.libpath / "system", {sfSystemModule})
-    service.serve(proc () =
-      let projectFile = mainCommandArg()
-      discard CompileModule(projectFile, {sfMainModule})
-    )
+    msgs.gErrorMax = high(int)  # do not stop after first error     
+    serve(MainCommand)
+    
   else: rawMessage(errInvalidCommandX, command)
 
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
index f4f6d0a42..0f0b76827 100755
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -235,15 +235,16 @@ proc LoadConfigs*(cfg: string) =
   if optSkipParentConfigFiles notin gGlobalOptions:
     for dir in parentDirs(pd, fromRoot=true, inclusive=false):
       readConfigFile(dir / cfg)
-    
-  if optSkipProjConfigFile notin gGlobalOptions and gProjectName.len != 0:
+  
+  if optSkipProjConfigFile notin gGlobalOptions:
     readConfigFile(pd / cfg)
     
-    var conffile = changeFileExt(gProjectFull, "cfg")
-    if conffile != pd / cfg and existsFile(conffile):
-      readConfigFile(conffile)
-      rawMessage(warnConfigDeprecated, conffile)
-    
-    # new project wide config file:
-    readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
+    if gProjectName.len != 0:
+      var conffile = changeFileExt(gProjectFull, "cfg")
+      if conffile != pd / cfg and existsFile(conffile):
+        readConfigFile(conffile)
+        rawMessage(warnConfigDeprecated, conffile)
+      
+      # new project wide config file:
+      readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
  
diff --git a/compiler/nimrod.cfg b/compiler/nimrod.cfg
index 42a5ed5f5..aa49729b9 100755
--- a/compiler/nimrod.cfg
+++ b/compiler/nimrod.cfg
@@ -1,9 +1,12 @@
 # Special configuration file for the Nimrod project
 
---hint[XDeclaredButNotUsed]=off
-path="llvm"
-path="$projectPath/.."
+mainModule:"nimrod.nim"
 
-path="$nimrod/packages/docutils"
+hint[XDeclaredButNotUsed]:off
+path:"llvm"
+path:"$projectPath/.."
+
+path:"$nimrod/packages/docutils"
+
+define:booting
 
---define:booting
diff --git a/compiler/options.nim b/compiler/options.nim
index 42fca1ad1..ba2a9eb41 100755
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -94,8 +94,8 @@ var
   gCmd*: TCommands = cmdNone  # the command
   gVerbosity*: int            # how verbose the compiler is
   gNumberOfProcessors*: int   # number of processors
-
   gWholeProject*: bool # for 'doc2': output any dependency
+  gEvalExpr*: string          # expression for idetools --eval
   
 const 
   genSubDir* = "nimcache"
diff --git a/compiler/passaux.nim b/compiler/passaux.nim
index 1ee6023c8..655b8ae68 100755
--- a/compiler/passaux.nim
+++ b/compiler/passaux.nim
@@ -26,10 +26,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode =
     incl(msgs.gNotes, hintProcessing)
     Message(n.info, hintProcessing, $idgen.gBackendId)
   
-proc verbosePass*(): TPass = 
-  initPass(result)
-  result.open = verboseOpen
-  result.process = verboseProcess
+const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
 
 proc cleanUp(c: PPassContext, n: PNode): PNode = 
   result = n                  
@@ -46,7 +43,5 @@ proc cleanUp(c: PPassContext, n: PNode): PNode =
   else: 
     nil
 
-proc cleanupPass*(): TPass = 
-  initPass(result)
-  result.process = cleanUp
-  result.close = cleanUp
+const cleanupPass* = makePass(process = cleanUp, close = cleanUp)
+
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 9b4a1b365..4941ac3b3 100755
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -18,21 +18,34 @@ import
 type  
   TPassContext* = object of TObject # the pass's context
     fromCache*: bool  # true if created by "openCached"
-    
+   
   PPassContext* = ref TPassContext
-  TPass* = tuple[
-    open: proc (module: PSym, filename: string): PPassContext {.nimcall.},
-    openCached: proc (module: PSym, filename: string,
-                     rd: PRodReader): PPassContext {.nimcall.},
-    close: proc (p: PPassContext, n: PNode): PNode {.nimcall.},
-    process: proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}]
-    
+
+  TPassOpen* = proc (module: PSym, filename: string): PPassContext {.nimcall.}
+  TPassOpenCached* = proc (module: PSym, filename: string,
+                           rd: PRodReader): PPassContext {.nimcall.}
+  TPassClose* = proc (p: PPassContext, n: PNode): PNode {.nimcall.}
+  TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}
+
+  TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached,
+                 process: TPassProcess, close: TPassClose]
+
+  TPassData* = tuple[input: PNode, closeOutput: Pnode]
+  TPasses* = openarray[TPass]
+
 # a pass is a tuple of procedure vars ``TPass.close`` may produce additional 
 # nodes. These are passed to the other close procedures. 
 # This mechanism used to be used for the instantiation of generics.
 
-proc registerPass*(p: TPass)
-proc initPass*(p: var TPass)
+proc makePass*(open: TPassOpen = nil,
+               openCached: TPassOpenCached = nil,
+               process: TPassProcess = nil,
+               close: TPassClose = nil): TPass =
+  result.open = open
+  result.openCached = openCached
+  result.close = close
+  result.process = process
+
   # This implements a memory preserving scheme: Top level statements are
   # processed in a pipeline. The compiler never looks at a whole module
   # any longer. However, this is simple to change, as new passes may perform
@@ -74,12 +87,28 @@ type
 
 var 
   gPasses: array[0..maxPasses - 1, TPass]
-  gPassesLen: int
+  gPassesLen*: int
+
+proc clearPasses* =
+  gPassesLen = 0
 
-proc registerPass(p: TPass) = 
+proc registerPass*(p: TPass) = 
   gPasses[gPassesLen] = p
   inc(gPassesLen)
 
+proc carryPass*(p: TPass, module: PSym, filename: string,
+                m: TPassData): TPassData =
+  var c = p.open(module, filename)
+  result.input = p.process(c, m.input)
+  result.closeOutput = if p.close != nil: p.close(c, m.closeOutput)
+                       else: m.closeOutput
+
+proc carryPasses*(nodes: PNode, module: PSym, file: string, passes: TPasses) =
+  var passdata: TPassData
+  passdata.input = nodes
+  for pass in passes:
+    passdata = carryPass(pass, module, file, passdata)
+
 proc openPasses(a: var TPassContextArray, module: PSym, filename: string) = 
   for i in countup(0, gPassesLen - 1): 
     if not isNil(gPasses[i].open): 
@@ -175,8 +204,3 @@ proc processModule(module: PSym, filename: string, stream: PLLStream,
     for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a)
     closePassesCached(a)
 
-proc initPass(p: var TPass) = 
-  p.open = nil
-  p.openCached = nil
-  p.close = nil
-  p.process = nil
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 5be9a2439..c89f06b37 100755
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -15,7 +15,6 @@ import
   intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
   condsyms, ropes, idents, crc, rodread, passes, importer, idgen, rodutils
 
-proc rodwritePass*(): TPass
 # implementation
 
 type 
@@ -583,10 +582,5 @@ proc myClose(c: PPassContext, n: PNode): PNode =
   writeRod(w)
   idgen.saveMaxIds(options.gProjectPath / options.gProjectName)
 
-proc rodwritePass(): TPass = 
-  initPass(result)
-  if optSymbolFiles in gGlobalOptions: 
-    result.open = myOpen
-    result.close = myClose
-    result.process = process
+const rodwritePass* = makePass(open = myOpen, close = myClose, process = process)
 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 911eafb08..86d9bf872 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -17,7 +17,6 @@ import
   semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting,
   evaltempl, patterns, parampatterns, sempass2
 
-proc semPass*(): TPass
 # implementation
 
 type 
@@ -288,9 +287,5 @@ proc myClose(context: PPassContext, n: PNode): PNode =
   popOwner()
   popProcCon(c)
 
-proc semPass(): TPass =
-  initPass(result)
-  result.open = myOpen
-  result.openCached = myOpenCached
-  result.close = myClose
-  result.process = myProcess
+const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
+
diff --git a/compiler/service.nim b/compiler/service.nim
index b1741b7bd..2ed2b75f5 100644
--- a/compiler/service.nim
+++ b/compiler/service.nim
@@ -56,17 +56,30 @@ proc ProcessCmdLine*(pass: TCmdLinePass, cmd: string) =
       rawMessage(errArgsNeedRunOption, [])
 
 proc serve*(action: proc (){.nimcall.}) =
-  var server = Socket()
-  let p = getConfigVar("server.port")
-  let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort
-  server.bindAddr(port, getConfigVar("server.address"))
-  var inp = "".TaintedString
-  server.listen()
-  new(stdoutSocket)
-  while true:
-    accept(server, stdoutSocket)
-    discard stdoutSocket.recvLine(inp)
-    processCmdLine(passCmd2, inp.string)
-    action()
-    stdoutSocket.send("\c\L")
-    stdoutSocket.close()
+  let typ = getConfigVar("server.type")
+  case typ
+  of "stdin":
+    while true:
+      var line = stdin.readLine.string
+      if line == "quit": quit()
+      processCmdLine(passCmd2, line)
+      action()
+  of "tcp", "":
+    var server = Socket()
+    let p = getConfigVar("server.port")
+    let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort
+    server.bindAddr(port, getConfigVar("server.address"))
+    var inp = "".TaintedString
+    server.listen()
+    new(stdoutSocket)
+    while true:
+      accept(server, stdoutSocket)
+      discard stdoutSocket.recvLine(inp)
+      processCmdLine(passCmd2, inp.string)
+      action()
+      stdoutSocket.send("\c\L")
+      stdoutSocket.close()
+  else:
+    echo "Invalid server.type:", typ
+    quit 1
+
diff --git a/compiler/transf.nim b/compiler/transf.nim
index dfa4095b4..5ba997524 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -696,12 +696,8 @@ when false:
     result = openTransf(module, filename)
     for m in items(rd.methods): methodDef(m, true)
 
-  proc transfPass(): TPass = 
-    initPass(result)
-    result.open = openTransf
-    result.openCached = openTransfCached
-    result.process = processTransf
-    result.close = processTransf # we need to process generics too!
+  const transfPass* = makePass(openTransf, openTransfCached,
+    processTransf, processTransf) # we need to process generics too!
   
 proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
   if nfTransf in n.flags or prc.kind in {skTemplate, skMacro}:
diff --git a/doc/advopt.txt b/doc/advopt.txt
index a6718572e..4b29400b6 100755
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -16,6 +16,7 @@ Advanced commands:
     --def                   list all possible definitions at position
     --context               list possible invokation context
     --usages                list all usages of the symbol at position
+    --eval                  evaluates an expression
 
 Advanced options:
   -m, --mainmodule:FILE     set the project main module
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 5db21d76a..0ef5e3ff5 100755
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -180,8 +180,12 @@ proc readLine*(s: PStream): TaintedString =
     if c == '\c': 
       c = readChar(s)
       break
-    elif c == '\L' or c == '\0': break
-    result.string.add(c)
+    if c == '\b':
+      result.string.setLen(result.len - 1)
+    elif c == '\L' or c == '\0':
+      break
+    else:
+      result.string.add(c)
 
 type
   PStringStream* = ref TStringStream ## a stream that encapsulates a string
id='n1423' href='#n1423'>1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503