proc compile(code: string): {.compileTime.} NimNode =
This is a syntax error because the proper syntax would be:
proc compile(code: string): NimNode {.compileTime.} =
Partly related: Ada is in a similar state. In the rationale of Ada 83, pragmas
were described as having _no influence on the meaning of the program_. Then,
Ada 95 came along and used pragmas for all sorts of things, including some
which changed the meaning of the code.
For Ada 2012, a solution was sought and found; it was a new part of the syntax
named _aspects_. So, instead of this:
procedure Flush;
pragma Import (StdCall, Flush, "glFlush");
You could now write
procedure Flush with
Import => True, Convention => StdCall, External_Name => "glFlush";
This is pretty close to how Nim pragmas already work, as they can already be
tied to some entity instead of being standalone. For me, the concept seems to
be closer to aspects than to traditional pragmas.
C# and Java have attributes/annotations which _have_ to be bound to some
entity. They are also part of the reflection descriptors, so they are pretty
different from what traditionally is called a pragma. However, some still have
the concept of being a hint to the compiler (for example, @Synchronized in
Java).
To summarize: Pragmas in a language are semantically placed on an axis
somewhere between „compiler hints“ and „part of the language semantics“. The
trend seems to be towards the latter, but the word _pragma_ is usually bound to
the former, so some languages call them differently. Nim calls them pragmas but
also supports the annotation/aspect semantics, and enables users to define „new
pragmas“ via macros. Which is conceptually not very different to what C# and
Java do, it is only much more powerful because the semantics can be given in
the macro implementation, while in Java, the semantics of an Annotation is
defined somewhere else.