first steps for compiler as a service

This commit is contained in:
Araq
2012-10-03 20:49:43 +02:00
parent b28fcdfa93
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,
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)

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"
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.} =

View File

@@ -159,6 +159,7 @@ Define Effect
systems. See the documentation of the `gc <gc.html>`_
for further information.
``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>
This document is a tutorial for the programming language *Nimrod*. After this
tutorial you will have a decent knowledge of Nimrod. This tutorial assumes
that you are familiar with basic programming concepts like variables, types
or statements.
This document is a tutorial for the programming language *Nimrod*.
This tutorial assumes that you are familiar with basic programming concepts
like variables, types or statements but is kept very basic. The manual
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`.
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.

View File

@@ -16,7 +16,9 @@ Introduction
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

View File

@@ -729,7 +729,8 @@ template InstantiateForRegion(allocator: expr) =
proc interiorAllocatedPtr*(p: pointer): pointer =
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)
proc deallocOsPages = deallocOsPages(allocator)

View File

@@ -818,7 +818,7 @@ proc getDirective(p: var TRstParser): string =
proc parseComment(p: var TRstParser): PRstNode =
case p.tok[p.idx].kind
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
else:
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):
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 =
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
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
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).
See the file ``install.txt`` for installation instructions. See the file

View File

@@ -8,23 +8,20 @@ Home
-- D. E. Knuth
**This page is about the Nimrod programming language, which combines Lisp's
power with Python's readability and C's performance.**
**Nimrod combines Lisp's power with Python's readability and C's performance.**
Welcome to Nimrod
-----------------
**Nimrod** is a new statically typed, imperative
programming language, that supports procedural, object oriented, functional
and generic programming styles while remaining simple and efficient.
A special feature that Nimrod inherited from Lisp is that Nimrod's abstract
syntax tree (*AST*) is part of the specification - this allows a powerful
macro system which allows domain specific languages.
Nimrod is a compiled, garbage-collected systems programming language
which has an excellent productivity/performance ratio. Nimrod's design
focuses on the 3E: efficiency, expressiveness, elegance (in the order of
priority).
**Nimrod** is a statically typed, imperative programming language that tries to
give the programmer ultimate power without compromises on runtime efficiency.
This means it focuses on compile-time mechanisms in all their
various forms. Beneath a nice infix/indentation based syntax with a
powerful (AST based, hygienic) macro system lies a semantic model that supports
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
shared memory heap is also provided for the increased efficiency that results
from that model.
.. container:: snippet
@@ -33,7 +30,8 @@ priority).
.. code-block:: nimrod
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
echo tokens.each(parseInt).max, " is the maximum."

View File

@@ -9,13 +9,15 @@ General
What is Nimrod?
---------------
Nimrod is a new statically typed, imperative
programming language, that supports procedural, functional, object oriented and
generic programming styles while remaining simple and efficient. A special
feature that Nimrod inherited from Lisp is that Nimrod's abstract syntax tree
(*AST*) is part of the specification - this allows a powerful macro system which
can be used to create domain specific languages. Nimrod does not sacrifice
flexibility for speed. You get both.
Nimrod is a statically typed, imperative programming language that tries to
give the programmer ultimate power without compromises on runtime efficiency.
This means it focuses on compile-time mechanisms in all their
various forms. Beneath a nice infix/indentation based syntax with a
powerful (AST based, hygienic) macro system lies a semantic model that supports
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
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?