@aedt, you should know there's AST for each statement and expression. It's the AST that converted to C, so that's how compiled it correctly.
Of course, using the same AST, you can compile directly to assembly too but I think kudos for Nim for compiling it to C. Several Scheme implementations are compiled to C too (Gambit and Chicken) but not as efficient as Nim (not to mention Gambit need mingw.dll if I want to use it in Windows)
Also, what made me use Nim is because the interoperability with C++ is very easy using Nim.
How reliably can Nim translate to C or C++?
As with any other compilers: nothing but a bunch of test cases, which is why code generation bug can still exist because covering all cases is almost impossible. Compiler's basic building block is a node in its hierarchical syntax tree, which maps to one or several (hopefully not too many) instructions in the target architecture (in which it's possible to create one based on any other language including C and C++). By ensuring these nodes produce correct instruction sequence, the whole tree can be assumed to be as correct, but of course it's not easy to prove and corner cases do exist, along with optimizations that can modify the tree wrong.
What amazes me is that Nim is a bit faster than some recent languages who compiles directly to machine language.
That should not be so surprising. A major aspect of the "speed" of a language is how much effort went into writing the backend of the compiler. C/C++ compilers have seen by far the most effort invested into them, so if you can piggyback on top of them (whether by generating C/C++ or appropriately leveraging the gcc/clang backend directly), this helps. C/C++ is not a good backend choice for all languages (for example, functional languages suffer from the lack of tail-call optimization guarantees and may have to use expensive workarounds), but if it fits your language design, it can be a very good option.
The other major factor is whether you can represent data structures in a hardware-friendly way. This is where the JVM hurts, but also some functional languages. Nim (like D or Rust) can avoid most unnecessary indirections that some other languages require and which can only sometimes be offset by a good optimizer.
I'll also note that C is not fast per se. C is generally fast for close-to-the-metal operations (such as iterating over contiguous arrays), but is fairly limited when it comes to higher order optimizations. A C compiler, for example, cannot generally do constant folding or common subexpression elimination for non-primitive types, often struggles with optimizing polymorphic behavior, or optimize reference count operations in the same way that Swift does. Even where it's possible in principle, such optimization steps are often too expensive.