first steps for compiler as a service
This commit is contained in:
parent
b28fcdfa93
commit
9fbee85cc9
11 changed files with 142 additions and 40 deletions
|
|
@ -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
71
compiler/service.nim
Normal 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()
|
||||||
|
|
@ -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.} =
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
================== =========================================================
|
================== =========================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
10
doc/tut1.txt
10
doc/tut1.txt
|
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -730,6 +730,7 @@ template InstantiateForRegion(allocator: expr) =
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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."
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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?
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue