Merge pull request #515 from gradha/pr_idetools_improvements
Idetools improvements
This commit is contained in:
commit
6feedc9cff
6 changed files with 234 additions and 51 deletions
153
doc/idetools.txt
153
doc/idetools.txt
|
|
@ -11,13 +11,13 @@
|
||||||
Nimrod differs from many other compilers in that it is really fast,
|
Nimrod differs from many other compilers in that it is really fast,
|
||||||
and being so fast makes it suited to provide external queries for
|
and being so fast makes it suited to provide external queries for
|
||||||
text editors about the source code being written. Through the
|
text editors about the source code being written. Through the
|
||||||
``idetools`` command of `the compiler <nimrodc.html>`_, any IDE can
|
`idetools`:idx: command of `the compiler <nimrodc.html>`_, any IDE
|
||||||
query a ``.nim`` source file and obtain useful information like
|
can query a ``.nim`` source file and obtain useful information like
|
||||||
definition of symbols or suggestions for completion.
|
definition of symbols or suggestions for completion.
|
||||||
|
|
||||||
This document will guide you through the available options. If you
|
This document will guide you through the available options. If you
|
||||||
want to look at practical examples of idetools support you can look
|
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>`_
|
integrations <https://github.com/Araq/Nimrod/wiki/Editor-Support>`_
|
||||||
already available.
|
already available.
|
||||||
|
|
||||||
|
|
@ -119,7 +119,9 @@ separators!).
|
||||||
|
|
||||||
The typical usage scenario for this option is to call it after the
|
The typical usage scenario for this option is to call it after the
|
||||||
user has typed the dot character for `the object oriented call
|
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
|
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
|
symbol is defined. Such latencies would be terrible for features
|
||||||
like symbol suggestion, plus why wait at all if we can avoid it?
|
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
|
The idetools command can be run as a compiler service (`caas`:idx:),
|
||||||
first launch the compiler and it will stay online as a server,
|
where you first launch the compiler and it will stay online as a
|
||||||
accepting queries in a telnet like fashion. The advantage of staying
|
server, accepting queries in a telnet like fashion. The advantage
|
||||||
on is that for many queries the compiler can cache the results of
|
of staying on is that for many queries the compiler can cache the
|
||||||
the compilation, and subsequent queries should be fast in the
|
results of the compilation, and subsequent queries should be fast
|
||||||
millisecond range, thus being responsive enough for IDEs.
|
in the millisecond range, thus being responsive enough for IDEs.
|
||||||
|
|
||||||
If you want to start the server using stdin/stdout as communication
|
If you want to start the server using stdin/stdout as communication
|
||||||
you need to type::
|
you need to type::
|
||||||
|
|
@ -188,7 +190,7 @@ of text it thinks necessary plus an empty line to indicate the end
|
||||||
of the answer.
|
of the answer.
|
||||||
|
|
||||||
You can find examples of client/server communication in the idetools
|
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
|
Parsing idetools output
|
||||||
|
|
@ -293,6 +295,22 @@ posterior instances of the iterator.
|
||||||
col 7: "iterates over any unicode character of the string `s`."
|
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
|
skLet
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
@ -308,6 +326,26 @@ skLet
|
||||||
col 7: ""
|
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
|
skMethod
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
@ -465,3 +503,96 @@ skVar
|
||||||
--> col 2: $MODULE.writeTempFile.output
|
--> col 2: $MODULE.writeTempFile.output
|
||||||
col 3: TFile
|
col 3: TFile
|
||||||
col 7: ""
|
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.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import unicode, sequtils
|
import unicode, sequtils, macros, re
|
||||||
|
|
||||||
proc test_enums() =
|
proc test_enums() =
|
||||||
var o: Tfile
|
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)
|
proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
|
||||||
|
|
||||||
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
|
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+)=(.*)"
|
||||||
|
|
|
||||||
|
|
@ -42,3 +42,18 @@ def\tskField\t$MODULE.TPerson.name\tbad_string\t
|
||||||
|
|
||||||
> idetools --track:$TESTNIM,43,7 --def $SILENT
|
> idetools --track:$TESTNIM,43,7 --def $SILENT
|
||||||
def\tskMethod\t$MODULE.eval\tproc \(PPlusExpr\): int\t
|
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
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
main.nim
|
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
|
> idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
|
||||||
skField\tx
|
skField\tx
|
||||||
skField\ty
|
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
|
> c --verbosity:0 --hints:on
|
||||||
SuccessX
|
SuccessX
|
||||||
|
|
||||||
|
|
|
||||||
26
tests/caas/suggest-invalid-source.txt
Normal file
26
tests/caas/suggest-invalid-source.txt
Normal 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
|
||||||
|
|
@ -2,45 +2,7 @@ import osproc, streams, os, strutils, re
|
||||||
|
|
||||||
## Compiler as a service tester.
|
## Compiler as a service tester.
|
||||||
##
|
##
|
||||||
## This test cases uses the txt files in the caas/ subdirectory.
|
## Please read docs/idetools.txt for information about this.
|
||||||
##
|
|
||||||
## 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
|
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -84,6 +46,8 @@ proc startNimrodSession(project, script: string, mode: TRunMode):
|
||||||
|
|
||||||
if mode == SymbolProcRun:
|
if mode == SymbolProcRun:
|
||||||
removeDir(nimcacheDir / result.nimcache)
|
removeDir(nimcacheDir / result.nimcache)
|
||||||
|
else:
|
||||||
|
removeDir(nimcacheDir / "nimcache")
|
||||||
|
|
||||||
if mode == CaasRun:
|
if mode == CaasRun:
|
||||||
result.nim = startProcess(NimrodBin, workingDir = dir,
|
result.nim = startProcess(NimrodBin, workingDir = dir,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue