first steps for compiler as a service

This commit is contained in:
Araq 2012-10-03 20:49:43 +02:00
commit 9fbee85cc9
11 changed files with 142 additions and 40 deletions

View file

@ -16,7 +16,7 @@ import
wordrecg, sem, semdata, idents, passes, docgen, extccomp, wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, ecmasgen, cgen, ecmasgen,
platform, nimconf, importer, passaux, depends, evals, types, idgen, platform, nimconf, importer, passaux, depends, evals, types, idgen,
tables, docgen2 tables, docgen2, service
const const
has_LLVM_Backend = false has_LLVM_Backend = false
@ -292,5 +292,16 @@ proc MainCommand =
gCmd = cmdIdeTools gCmd = cmdIdeTools
wantMainModule() wantMainModule()
CommandSuggest() 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) else: rawMessage(errInvalidCommandX, command)

71
compiler/service.nim Normal file
View file

@ -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()

View file

@ -18,6 +18,11 @@ const
sectionContext = "con" sectionContext = "con"
sectionUsage = "use" sectionUsage = "use"
proc SuggestWriteln(s: string) =
if gSilence == 0:
Writeln(stdout, s)
proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string = proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
result = section result = section
result.add(sep) result.add(sep)
@ -51,7 +56,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
proc suggestField(c: PContext, s: PSym, outputs: var int) = proc suggestField(c: PContext, s: PSym, outputs: var int) =
if filterSym(s) and fieldVisible(c, s): if filterSym(s) and fieldVisible(c, s):
OutWriteln(SymToStr(s, isLocal=true, sectionSuggest)) SuggestWriteln(SymToStr(s, isLocal=true, sectionSuggest))
inc outputs inc outputs
when not defined(nimhygiene): when not defined(nimhygiene):
@ -62,7 +67,7 @@ template wholeSymTab(cond, section: expr) {.immediate.} =
for item in items(c.tab.stack[i]): for item in items(c.tab.stack[i]):
let it {.inject.} = item let it {.inject.} = item
if cond: if cond:
OutWriteln(SymToStr(it, isLocal = i > ModuleTablePos, section)) SuggestWriteln(SymToStr(it, isLocal = i > ModuleTablePos, section))
inc outputs inc outputs
proc suggestSymList(c: PContext, list: PNode, outputs: var int) = 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 i in countdown(c.tab.tos-1, 1):
for it in items(c.tab.stack[i]): for it in items(c.tab.stack[i]):
if filterSym(it): if filterSym(it):
OutWriteln(SymToStr(it, isLocal = i > ModuleTablePos, sectionSuggest)) SuggestWriteln(SymToStr(it, isLocal = i > ModuleTablePos, sectionSuggest))
inc outputs inc outputs
proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) = 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: # all symbols accessible, because we are in the current module:
for it in items(c.tab.stack[ModuleTablePos]): for it in items(c.tab.stack[ModuleTablePos]):
if filterSym(it): if filterSym(it):
OutWriteln(SymToStr(it, isLocal=false, sectionSuggest)) SuggestWriteln(SymToStr(it, isLocal=false, sectionSuggest))
inc outputs inc outputs
else: else:
for it in items(n.sym.tab): for it in items(n.sym.tab):
if filterSym(it): if filterSym(it):
OutWriteln(SymToStr(it, isLocal=false, sectionSuggest)) SuggestWriteln(SymToStr(it, isLocal=false, sectionSuggest))
inc outputs inc outputs
else: else:
# fallback: # fallback:
@ -224,15 +229,15 @@ var
proc findUsages(node: PNode, s: PSym) = proc findUsages(node: PNode, s: PSym) =
if usageSym == nil and isTracked(node.info, s.name.s.len): if usageSym == nil and isTracked(node.info, s.name.s.len):
usageSym = s usageSym = s
OutWriteln(SymToStr(s, isLocal=false, sectionUsage)) SuggestWriteln(SymToStr(s, isLocal=false, sectionUsage))
elif s == usageSym: elif s == usageSym:
if lastLineInfo != node.info: if lastLineInfo != node.info:
OutWriteln(SymToStr(s, isLocal=false, sectionUsage, node.info)) SuggestWriteln(SymToStr(s, isLocal=false, sectionUsage, node.info))
lastLineInfo = node.info lastLineInfo = node.info
proc findDefinition(node: PNode, s: PSym) = proc findDefinition(node: PNode, s: PSym) =
if isTracked(node.info, s.name.s.len): if isTracked(node.info, s.name.s.len):
OutWriteln(SymToStr(s, isLocal=false, sectionDef)) SuggestWriteln(SymToStr(s, isLocal=false, sectionDef))
quit(0) quit(0)
proc suggestSym*(n: PNode, s: PSym) {.inline.} = proc suggestSym*(n: PNode, s: PSym) {.inline.} =

View file

@ -159,6 +159,7 @@ Define Effect
systems. See the documentation of the `gc <gc.html>`_ systems. See the documentation of the `gc <gc.html>`_
for further information. for further information.
``nodejs`` The EcmaScript target is actually ``node.js``. ``nodejs`` The EcmaScript target is actually ``node.js``.
``ssl`` Enables OpenSSL support for the sockets module.
================== ========================================================= ================== =========================================================

View file

@ -16,10 +16,10 @@ Introduction
</p></blockquote> </p></blockquote>
This document is a tutorial for the programming language *Nimrod*. After this This document is a tutorial for the programming language *Nimrod*.
tutorial you will have a decent knowledge of Nimrod. This tutorial assumes This tutorial assumes that you are familiar with basic programming concepts
that you are familiar with basic programming concepts like variables, types like variables, types or statements but is kept very basic. The manual
or statements. contains many more examples of the advanced language features.
@ -593,7 +593,7 @@ caller, a ``var`` parameter can be used:
In the example, ``res`` and ``remainder`` are `var parameters`. In the example, ``res`` and ``remainder`` are `var parameters`.
Var parameters can be modified by the procedure and the changes are Var parameters can be modified by the procedure and the changes are
visible to the caller. Note that the above example would better make usage of visible to the caller. Note that the above example would better make use of
a tuple as a return value instead of using var parameters. a tuple as a return value instead of using var parameters.

View file

@ -16,7 +16,9 @@ Introduction
This document is a tutorial for the advanced constructs of the *Nimrod* This document is a tutorial for the advanced constructs of the *Nimrod*
programming language. programming language. **Note that this document is somewhat obsolete as
the `manual <manual.html>`_ contains many more examples of the advanced
language features.**
Pragmas Pragmas

View file

@ -729,7 +729,8 @@ template InstantiateForRegion(allocator: expr) =
proc interiorAllocatedPtr*(p: pointer): pointer = proc interiorAllocatedPtr*(p: pointer): pointer =
result = interiorAllocatedPtr(allocator, p) result = interiorAllocatedPtr(allocator, p)
proc isAllocatedPtr*(p: pointer): bool = proc isAllocatedPtr*(p: pointer): bool =
let p = cast[pointer](cast[TAddress](p)-%TAddress(sizeof(TCell)))
result = isAllocatedPtr(allocator, p) result = isAllocatedPtr(allocator, p)
proc deallocOsPages = deallocOsPages(allocator) proc deallocOsPages = deallocOsPages(allocator)

View file

@ -818,7 +818,7 @@ proc getDirective(p: var TRstParser): string =
proc parseComment(p: var TRstParser): PRstNode = proc parseComment(p: var TRstParser): PRstNode =
case p.tok[p.idx].kind case p.tok[p.idx].kind
of tkIndent, tkEof: of tkIndent, tkEof:
if p.tok[p.idx + 1].kind == tkIndent: if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent:
inc(p.idx) # empty comment inc(p.idx) # empty comment
else: else:
var indent = p.tok[p.idx].ival var indent = p.tok[p.idx].ival
@ -1348,9 +1348,20 @@ proc parseSectionWrapper(p: var TRstParser): PRstNode =
while (result.kind == rnInner) and (len(result) == 1): while (result.kind == rnInner) and (len(result) == 1):
result = result.sons[0] result = result.sons[0]
proc `$`(t: TToken): string =
result = $t.kind & ' ' & (if isNil(t.symbol): "NIL" else: t.symbol)
proc parseDoc(p: var TRstParser): PRstNode = proc parseDoc(p: var TRstParser): PRstNode =
result = parseSectionWrapper(p) result = parseSectionWrapper(p)
if p.tok[p.idx].kind != tkEof: rstMessage(p, meGeneralParseError) if p.tok[p.idx].kind != tkEof:
when false:
assert isAllocatedPtr(cast[pointer](p.tok))
for i in 0 .. high(p.tok):
assert isNil(p.tok[i].symbol) or
isAllocatedPtr(cast[pointer](p.tok[i].symbol))
echo "index: ", p.idx, " length: ", high(p.tok), "##",
p.tok[p.idx-1], p.tok[p.idx], p.tok[p.idx+1]
rstMessage(p, meGeneralParseError)
type type
TDirFlag = enum TDirFlag = enum

View file

@ -11,7 +11,7 @@ can be used to create domain specific languages.
*Nimrod* is a compiled, garbage-collected systems programming language *Nimrod* is a compiled, garbage-collected systems programming language
which has an excellent productivity/performance ratio. Nimrod's design which has an excellent productivity/performance ratio. Nimrod's design
focuses on the 3E: efficiency, expressiveness, elegance (in the order of focuses on efficiency, expressiveness, elegance (in the order of
priority). priority).
See the file ``install.txt`` for installation instructions. See the file See the file ``install.txt`` for installation instructions. See the file

View file

@ -8,23 +8,20 @@ Home
-- D. E. Knuth -- D. E. Knuth
**This page is about the Nimrod programming language, which combines Lisp's **Nimrod combines Lisp's power with Python's readability and C's performance.**
power with Python's readability and C's performance.**
Welcome to Nimrod Welcome to Nimrod
----------------- -----------------
**Nimrod** is a new statically typed, imperative **Nimrod** is a statically typed, imperative programming language that tries to
programming language, that supports procedural, object oriented, functional give the programmer ultimate power without compromises on runtime efficiency.
and generic programming styles while remaining simple and efficient. This means it focuses on compile-time mechanisms in all their
A special feature that Nimrod inherited from Lisp is that Nimrod's abstract various forms. Beneath a nice infix/indentation based syntax with a
syntax tree (*AST*) is part of the specification - this allows a powerful powerful (AST based, hygienic) macro system lies a semantic model that supports
macro system which allows domain specific languages. a soft realtime GC on thread local heaps. Asynchronous message passing is used
between threads, so no "stop the world" mechanism is necessary. An unsafe
Nimrod is a compiled, garbage-collected systems programming language shared memory heap is also provided for the increased efficiency that results
which has an excellent productivity/performance ratio. Nimrod's design from that model.
focuses on the 3E: efficiency, expressiveness, elegance (in the order of
priority).
.. container:: snippet .. container:: snippet
@ -33,7 +30,8 @@ priority).
.. code-block:: nimrod .. code-block:: nimrod
import strutils import strutils
echo "Type in a list of ints of ints (separate by whitespace): " # Prints the maximum integer from a list of integers
# delimited by whitespace read from stdin.
let tokens = stdin.readLine.split let tokens = stdin.readLine.split
echo tokens.each(parseInt).max, " is the maximum." echo tokens.each(parseInt).max, " is the maximum."

View file

@ -9,13 +9,15 @@ General
What is Nimrod? What is Nimrod?
--------------- ---------------
Nimrod is a new statically typed, imperative Nimrod is a statically typed, imperative programming language that tries to
programming language, that supports procedural, functional, object oriented and give the programmer ultimate power without compromises on runtime efficiency.
generic programming styles while remaining simple and efficient. A special This means it focuses on compile-time mechanisms in all their
feature that Nimrod inherited from Lisp is that Nimrod's abstract syntax tree various forms. Beneath a nice infix/indentation based syntax with a
(*AST*) is part of the specification - this allows a powerful macro system which powerful (AST based, hygienic) macro system lies a semantic model that supports
can be used to create domain specific languages. Nimrod does not sacrifice a soft realtime GC on thread local heaps. Asynchronous message passing is used
flexibility for speed. You get both. between threads, so no "stop the world" mechanism is necessary. An unsafe
shared memory heap is also provided for the increased efficiency that results
from that model.
.. ..
Don't give me that marketing crap. What is Nimrod? Don't give me that marketing crap. What is Nimrod?