Merge pull request #515 from gradha/pr_idetools_improvements

Idetools improvements
This commit is contained in:
Araq
2013-07-07 16:05:17 -07:00
6 changed files with 234 additions and 51 deletions

View File

@@ -11,13 +11,13 @@
Nimrod differs from many other compilers in that it is really fast,
and being so fast makes it suited to provide external queries for
text editors about the source code being written. Through the
``idetools`` command of `the compiler <nimrodc.html>`_, any IDE can
query a ``.nim`` source file and obtain useful information like
`idetools`:idx: command of `the compiler <nimrodc.html>`_, any IDE
can query a ``.nim`` source file and obtain useful information like
definition of symbols or suggestions for completion.
This document will guide you through the available options. If you
want to look at practical examples of idetools support you can look
at the test files found in ``tests/caas/*.txt`` or `various editor
at the test files found in the `Test suite`_ or `various editor
integrations <https://github.com/Araq/Nimrod/wiki/Editor-Support>`_
already available.
@@ -119,7 +119,9 @@ separators!).
The typical usage scenario for this option is to call it after the
user has typed the dot character for `the object oriented call
syntax <tut2.html#method-call-syntax>`_.
syntax <tut2.html#method-call-syntax>`_. Idetools will try to return
the suggestions sorted first by scope (from innermost to outermost)
and then by item name.
Invokation context
@@ -162,12 +164,12 @@ clicks it and after a second or two the IDE displays where that
symbol is defined. Such latencies would be terrible for features
like symbol suggestion, plus why wait at all if we can avoid it?
The idetools command can be run as a compiler service, where you
first launch the compiler and it will stay online as a server,
accepting queries in a telnet like fashion. The advantage of staying
on is that for many queries the compiler can cache the results of
the compilation, and subsequent queries should be fast in the
millisecond range, thus being responsive enough for IDEs.
The idetools command can be run as a compiler service (`caas`:idx:),
where you first launch the compiler and it will stay online as a
server, accepting queries in a telnet like fashion. The advantage
of staying on is that for many queries the compiler can cache the
results of the compilation, and subsequent queries should be fast
in the millisecond range, thus being responsive enough for IDEs.
If you want to start the server using stdin/stdout as communication
you need to type::
@@ -188,7 +190,7 @@ of text it thinks necessary plus an empty line to indicate the end
of the answer.
You can find examples of client/server communication in the idetools
tests found in ``tests/caas/*.txt``.
tests found in the `Test suite`_.
Parsing idetools output
@@ -293,6 +295,22 @@ posterior instances of the iterator.
col 7: "iterates over any unicode character of the string `s`."
skLabel
-------
| **Third column**: module + [n scope nesting] + name.
| **Fourth column**: always the empty string.
| **Docstring**: always the empty string.
.. code-block:: nimrod
proc test(text: string) =
var found = -1
block loops:
--> col 2: $MODULE.test.loops
col 3: ""
col 7: ""
skLet
-----
@@ -308,6 +326,26 @@ skLet
col 7: ""
skMacro
-------
The fourth column will be the empty string if the macro is being
defined, since at that point in the file the parser hasn't processed
the full line yet. The signature will be returned complete in
posterior instances of the macro.
| **Third column**: module + [n scope nesting] + macro name.
| **Fourth column**: signature of the macro including return type.
| **Docstring**: docstring if available.
.. code-block:: nimrod
proc testMacro() =
expect(EArithmetic):
--> col 2: idetools_api.expect
col 3: proc (varargs[expr], stmt): stmt
col 7: ""
skMethod
--------
@@ -465,3 +503,96 @@ skVar
--> col 2: $MODULE.writeTempFile.output
col 3: TFile
col 7: ""
Test suite
==========
To verify that idetools is working properly there are files in the
``tests/caas/`` directory which provide unit testing. If you find
odd idetools behaviour and are able to reproduce it, you are welcome
to report it as a bug and add a test to the suite to avoid future
regressions.
Running the test suite
----------------------
At the moment idetools support is still in development so the test
suite is not integrated with the main test suite and you have to
run it manually. First you have to compile the tester::
$ cd my/nimrod/checkout
$ nimrod c tests/tester.nim
Running the tester without parameters will display some options.
To run the caas test suite (and other special tests) you need to
use the `special` command. You need to run this command from the
root of the checkout or it won't be able to open the required files::
$ ./tests/tester special
However this is a roundabout way of running the test suite. You can
also compile and run ``tests/caasdriver.nim`` manually. In fact,
running it manually will allow you to specify special parameters
too. Example::
$ cd my/nimrod/checkout/tests
$ nimrod c caasdriver.nim
Running the ``caasdriver`` without parameters will attempt to process
all the test cases in all three operation modes. If a test succeeds
nothing will be printed and the process will exit with zero. If any
test fails, the specific line of the test preceeding the failure
and the failure itself will be dumped to stdout, along with a final
indicator of the success state and operation mode. You can pass the
parameter ``verbose`` to force all output even on successfull tests.
The normal operation mode is called ``ProcRun`` and it involves
starting a process for each command or query, similar to running
manually the Nimrod compiler from the commandline. The ``CaasRun``
mode starts a server process to answer all queries. The ``SymbolProcRun``
mode is used by compiler developers. This means that running all
tests involves processing all ``*.txt`` files three times, which
can be quite time consuming.
If you don't want to run all the test case files you can pass any
substring as a parameter to ``caasdriver``. Only files matching the
passed substring will be run. The filtering doesn't use any globbing
metacharacters, it's a plain match. For example, to run only
``*-compile*.txt`` tests in verbose mode::
./caasdriver verbose -compile
Test case file format
---------------------
All the ``tests/caas/*.txt`` files encode a session with the compiler:
* The first line indicates the main project file.
* Lines starting with ``>`` indicate a command to be sent to the
compiler and the lines following a command include checks for
expected or forbidden output (``!`` for forbidden).
* If a line starts with ``#`` it will be ignored completely, so you
can use that for comments.
* Since some cases are specific to either ``ProcRun`` or ``CaasRun``
modes, you can prefix a line with the mode and the line will be
processed only in that mode.
* The rest of the line is treated as a `regular expression <re.html>`_,
so be careful escaping metacharacters like parenthesis.
Before the line is processed as a regular expression, some basic
variables are searched for and replaced in the tests. The variables
which will be replaced are:
* **$TESTNIM**: filename specified in the first line of the script.
* **$MODULE**: like $TESTNIM but without extension, useful for
expected output.
When adding a test case to the suite it is a good idea to write a
few comments about what the test is meant to verify.

View File

@@ -1,4 +1,4 @@
import unicode, sequtils
import unicode, sequtils, macros, re
proc test_enums() =
var o: Tfile
@@ -41,3 +41,44 @@ proc newLit(x: int): PLiteral = PLiteral(x: x)
proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
proc findVowelPosition(text: string) =
var found = -1
block loops:
for i, letter in pairs(text):
for j in ['a', 'e', 'i', 'o', 'u']:
if letter == j:
found = i
break loops # leave both for-loops
echo found
findVowelPosition("Zerg") # should output 1, position of vowel.
macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
## Expect docstrings
let exp = callsite()
template expectBody(errorTypes, lineInfoLit: expr,
body: stmt): PNimrodNode {.dirty.} =
try:
body
assert false
except errorTypes:
nil
var body = exp[exp.len - 1]
var errorTypes = newNimNode(nnkBracket)
for i in countup(1, exp.len - 2):
errorTypes.add(exp[i])
result = getAst(expectBody(errorTypes, exp.lineinfo, body))
proc err =
raise newException(EArithmetic, "some exception")
proc testMacro() =
expect(EArithmetic):
err()
testMacro()
let notAModule = re"(\w+)=(.*)"

View File

@@ -42,3 +42,18 @@ def\tskField\t$MODULE.TPerson.name\tbad_string\t
> idetools --track:$TESTNIM,43,7 --def $SILENT
def\tskMethod\t$MODULE.eval\tproc \(PPlusExpr\): int\t
> idetools --track:$TESTNIM,47,8 --def $SILENT
def\tskLabel\t$MODULE.findVowelPosition.loops\t\t
# For some reason the use of the label with break displaces its position.
> idetools --track:$TESTNIM,52,16 --def $SILENT
def\tskLabel\t$MODULE.findVowelPosition.loops\t\t
# Displaced macro usage by one character.
> idetools --track:$TESTNIM,80,2 --def $SILENT
def\tskMacro\t$MODULE.expect\tproc \(varargs\[expr\], stmt\): stmt\t
# The syntax for extended raw string literals should not be returned as module
# but as the proc re() inside the re module.
> idetools --track:$TESTNIM,84,17 --def $SILENT
!def\tskModule

View File

@@ -1,7 +1,13 @@
main.nim
# This example shows how the suggest feature can be used on a partial file
# using the --trackDirty switch.
> idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
skField\tx
skField\ty
# Repeating the query in caas should work always and retrieve same output.
CaasRun > idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
CaasRun skField\tx
CaasRun skField\ty
> c --verbosity:0 --hints:on
SuccessX

View File

@@ -0,0 +1,26 @@
main_dirty.nim
# A variant of the suggest-compile.txt, instead of using a "base" correct
# source, this one uses the "broken" main_dirty.nim which won't compile. The
# test tries to stress idetools to still provide a valid answer if possible,
# and at least provide the same output with repeated queries rather than dying
# after the first compilation error.
# The first query should work and provide valid suggestions.
> idetools --track:$TESTNIM,12,6 --suggest $SILENT
skField\tx
skField\ty
# Repeating the query should work too.
> idetools --track:$TESTNIM,12,6 --suggest $SILENT
skField\tx
skField\ty
# Expect now a compilation failure.
> c
!SuccessX
invalid indentation
# Repeating suggestions *after broken compilation* should work too.
> idetools --track:$TESTNIM,12,6 --suggest $SILENT
skField\tx
skField\ty

View File

@@ -2,45 +2,7 @@ import osproc, streams, os, strutils, re
## Compiler as a service tester.
##
## This test cases uses the txt files in the caas/ subdirectory.
##
## Each of the text files inside encodes a session with the compiler:
##
## The first line indicates the main project file.
##
## Lines starting with '>' indicate a command to be sent to the compiler and
## the lines following a command include checks for expected or forbidden
## output (! for forbidden).
##
## If a line starts with '#' it will be ignored completely, so you can use that
## for comments.
##
## All the tests are run both in ProcRun (each command creates a separate
## process) and CaasRun (first command starts up a server and it is reused for
## the rest) modes. Since some cases are specific to either ProcRun or CaasRun
## modes, you can prefix a line with the mode and the line will be processed
## only in that mode.
##
## The rest of the line is treated as a regular expression, so be careful
## escaping metacharacters like parenthesis. Before the line is processed as a
## regular expression, some basic variables are searched for and replaced in
## the tests. The variables which will be replaced are:
##
## - $TESTNIM: filename specified in the first line of the script.
## - $MODULE: like $TESTNIM but without extension, useful for expected output.
##
## You can optionally pass parameters at the command line to modify the
## behaviour of the test suite. By default only tests which fail will be echoed
## to stdout. If you want to see all the output pass the word "verbose" as a
## parameter.
##
## If you don't want to run all the test case files, you can pass any substring
## as a parameter. Only files matching the passed substring will be run. The
## filtering doesn't use any globbing metacharacters, it's a plain match.
##
## Example to run only "*-compile*.txt" tests in verbose mode:
##
## ./caasdriver verbose -compile
## Please read docs/idetools.txt for information about this.
type
@@ -84,6 +46,8 @@ proc startNimrodSession(project, script: string, mode: TRunMode):
if mode == SymbolProcRun:
removeDir(nimcacheDir / result.nimcache)
else:
removeDir(nimcacheDir / "nimcache")
if mode == CaasRun:
result.nim = startProcess(NimrodBin, workingDir = dir,