I would like to parse the contents of a Nim file into AST, like so- pseudocode:
macro foo(): untyped=
result = includeAsAst "file.nim"
So that it would be equivalent to
include "file.nim"
except that only the AST is returned after parsing, and no further compilation happens.
I know I can do this:
macro foo(): untyped=
result = parseStmt(readFile("file.nim"), "file.nim")
But that does not support source code filters.It's probably a bit hacky, but one seems to be able to do this so you could make foo emit expand: include ....
import std/macros
macro expand(t: typed): untyped =
echo t.treeRepr
t
expand:
include std/strutils
@ElegantBeef That's perfect, thank you!!! I'd say if it works and you can't make it prettier it's idiomatic :) Now trying to adjust it a bit, in my case std/strutils is a const string {.strdefine.} that contains /path/to/file.nim eindeutig @Araq I was looking into importing the compiler for another purpose as well! I encountered two hitches.
First was the path- import std/strutils is unambiguous, but can I rely on the compiler source being in [libPath]/../compiler?
The other was- where is the compiler's high level interface? I only found a bunch of interna and had a hard time finding docs or some kind of starting point.
The other was- where is the compiler's high level interface?
There is https://github.com/nim-lang/Nim/tree/devel/tests/compilerapi for an introduction.
@ElegantBeef
I did it! This will work fine. Thanks for the help!
import macros
const sourcePath {.strdefine.} = ""
macro dyninclude(path: static[string]) =
newNimNode(nnkIncludeStmt).add(newIdentNode(path))
macro expand(t: typed): untyped =
echo t.treeRepr
t
expand:
dyninclude(sourcePath)
$ nim c -d:sourcePath=foo.nim inc.nim
@Araq
I managed to bootstrap the compiler like so. Works fine!
import std/os
let std = findNimStdLibCompileTime()
const sourcePath = "foo.nim"
let i = createInterpreter(sourcePath, [std, parentDir(currentSourcePath), std / "pure", std / "core"])
I'm pretty amazed once again, I've never seen that feature in any language. But, of course, the one language to rule them all would do that.
It's probably more practical for my use case though to keep my current method of calling an installed nim binary with a startProcess. The compiler adds a lot of compilation time to a small project, and calling it you can use the same binary with different Nim versions. And if I were to ship the compiler-included binary, I'd still have to ship a standard library and possibly nimble directories, and the easiest way to do that is to just ask people to install a Nim compiler. I suppose it would be possible to compile a dynlib with the nim compiler but it's easier at this point to just call it.
Still salivating, drunk with power, that I can have my own Nim compiler though! I hope I'll find something I can use that for.
I hope I'll find something I can use that for.
If you can avoid it, better avoid it. While the API is more stable than it used to be, there is a new Nim implementation in development that most likely will not support it.
Good to know!! If there's a new way to have it I'm using that!
Thinking about having a nimcompiler.dll that exposes the command line API in more detail would be really cool. Not making a case that it would be worth it necessarily- but it would be a whole next level of a nerd snipe.