diff --git a/compiler/main.nim b/compiler/main.nim
index 37feabd17..dec393c50 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
+ tables, docgen2, service
const
has_LLVM_Backend = false
@@ -292,5 +292,16 @@ proc MainCommand =
gCmd = cmdIdeTools
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 = gProjectFull
+ discard CompileModule(projectFile, {sfMainModule})
+ )
else: rawMessage(errInvalidCommandX, command)
diff --git a/compiler/service.nim b/compiler/service.nim
new file mode 100644
index 000000000..95fb11022
--- /dev/null
+++ b/compiler/service.nim
@@ -0,0 +1,71 @@
+#
+#
+# The Nimrod Compiler
+# (c) Copyright 2012 Andreas Rumpf
+#
+# See the file "copying.txt", included in this
+# distribution, for details about the copyright.
+#
+
+## Implements the "compiler as a service" feature.
+
+import
+ sockets,
+ times, commands, options, msgs, nimconf,
+ extccomp, strutils, os, platform, main, parseopt
+
+# 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
+# repeated CRC calculations may turn out to be too slow.
+
+var
+ arguments: string = "" # the arguments to be passed to the program that
+ # should be run
+
+proc ProcessCmdLine(pass: TCmdLinePass, cmd: string) =
+ # XXX remove duplication with nimrod.nim
+ var p = parseopt.initOptParser(cmd)
+ var argsCount = 0
+ while true:
+ parseopt.next(p)
+ case p.kind
+ of cmdEnd: break
+ of cmdLongOption, cmdShortOption:
+ # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
+ # we fix this here
+ var bracketLe = strutils.find(p.key, '[')
+ if bracketLe >= 0:
+ var key = substr(p.key, 0, bracketLe - 1)
+ var val = substr(p.key, bracketLe + 1) & ':' & p.val
+ ProcessSwitch(key, val, pass, gCmdLineInfo)
+ else:
+ ProcessSwitch(p.key, p.val, pass, gCmdLineInfo)
+ of cmdArgument:
+ if argsCount == 0:
+ options.command = p.key
+ else:
+ if pass == passCmd1: options.commandArgs.add p.key
+ if argsCount == 1:
+ # support UNIX style filenames anywhere for portable build scripts:
+ options.gProjectName = unixToNativePath(p.key)
+ arguments = cmdLineRest(p)
+ break
+ inc argsCount
+
+ if pass == passCmd2:
+ if optRun notin gGlobalOptions and arguments != "":
+ 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()
+ while true:
+ var client = InvalidSocket
+ accept(server, client)
+ discard client.recvLine(inp)
+ processCmdLine(passCmd2, inp.string)
+ action()
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index daecf44b8..d33f9a7bd 100755
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -18,6 +18,11 @@ const
sectionContext = "con"
sectionUsage = "use"
+proc SuggestWriteln(s: string) =
+ if gSilence == 0:
+ Writeln(stdout, s)
+
+
proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
result = section
result.add(sep)
@@ -51,7 +56,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
proc suggestField(c: PContext, s: PSym, outputs: var int) =
if filterSym(s) and fieldVisible(c, s):
- OutWriteln(SymToStr(s, isLocal=true, sectionSuggest))
+ SuggestWriteln(SymToStr(s, isLocal=true, sectionSuggest))
inc outputs
when not defined(nimhygiene):
@@ -62,7 +67,7 @@ template wholeSymTab(cond, section: expr) {.immediate.} =
for item in items(c.tab.stack[i]):
let it {.inject.} = item
if cond:
- OutWriteln(SymToStr(it, isLocal = i > ModuleTablePos, section))
+ SuggestWriteln(SymToStr(it, isLocal = i > ModuleTablePos, section))
inc outputs
proc suggestSymList(c: PContext, list: PNode, outputs: var int) =
@@ -120,7 +125,7 @@ proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
for i in countdown(c.tab.tos-1, 1):
for it in items(c.tab.stack[i]):
if filterSym(it):
- OutWriteln(SymToStr(it, isLocal = i > ModuleTablePos, sectionSuggest))
+ SuggestWriteln(SymToStr(it, isLocal = i > ModuleTablePos, sectionSuggest))
inc outputs
proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
@@ -134,12 +139,12 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
# all symbols accessible, because we are in the current module:
for it in items(c.tab.stack[ModuleTablePos]):
if filterSym(it):
- OutWriteln(SymToStr(it, isLocal=false, sectionSuggest))
+ SuggestWriteln(SymToStr(it, isLocal=false, sectionSuggest))
inc outputs
else:
for it in items(n.sym.tab):
if filterSym(it):
- OutWriteln(SymToStr(it, isLocal=false, sectionSuggest))
+ SuggestWriteln(SymToStr(it, isLocal=false, sectionSuggest))
inc outputs
else:
# fallback:
@@ -224,15 +229,15 @@ var
proc findUsages(node: PNode, s: PSym) =
if usageSym == nil and isTracked(node.info, s.name.s.len):
usageSym = s
- OutWriteln(SymToStr(s, isLocal=false, sectionUsage))
+ SuggestWriteln(SymToStr(s, isLocal=false, sectionUsage))
elif s == usageSym:
if lastLineInfo != node.info:
- OutWriteln(SymToStr(s, isLocal=false, sectionUsage, node.info))
+ SuggestWriteln(SymToStr(s, isLocal=false, sectionUsage, node.info))
lastLineInfo = node.info
proc findDefinition(node: PNode, s: PSym) =
if isTracked(node.info, s.name.s.len):
- OutWriteln(SymToStr(s, isLocal=false, sectionDef))
+ SuggestWriteln(SymToStr(s, isLocal=false, sectionDef))
quit(0)
proc suggestSym*(n: PNode, s: PSym) {.inline.} =
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index 7b969c3bb..117d226a6 100755
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -159,6 +159,7 @@ Define Effect
systems. See the documentation of the `gc