As I define new types in a DSL language, I have templates that generate new
templates code for operations supported by these new types. That's code
generation.
Also, these types don't support automatic coercion. That is, if the user wrote
an int constant, I don't want the nim compiler automatically transform it to a
float without the user knowing it. And I want to have precise error messages
when the user does type errors when using these new types.
Let's try to reproduce the problem:
import macros
type
Real = object
val: float
# Generated templates for the new type Real
###########################################
template `==`(a: Real, b: float): bool =
a.val == b
template `==`(a: float, b: Real): bool =
a == b.val
# User code
###########
let x = Real(val: 3)
echo x == 4
echo 2 == x
dumpTree:
let x = Real(val: 3)
echo x == 4
echo 2 == x
Run
When this code is compiled, there are no error messages and compilation
succeeds. We see from the dumpTree that the compiler has parsed int literals
but it has coerced (automatically converted) the **4** and **2** literal int
values to floats and was able to resolve the == operators! That's not what I
want because the DSL does not mix types the way Nim does...
OK, that's because the templates use typed arguments. Let's change them to
untyped ones.
import macros
type
Real = object
val: float
# Generated templates for the new type Real
###########################################
template `==`(a: Real, b: untyped): bool =
if typeof(b) is not float:
raise newException(CatchableError, "Second param " & $b & " is not a
float")
a.val == b
template `==`(a: untyped, b: Real): bool =
if typeof(a) is not float:
raise newException(CatchableError, "First param " & $a & " is not a
float")
a == b.val
# User code
###########
let x = Real(val: 3)
echo x == 4
echo 2 == x
Run
Again, the user code compiles without error, but now at least I'm able to catch
the type mismatch at run time! But the user does not know when he compile his
code that there are syntax (types) errors. He will discover later when
executing the code, too late!
$ ./foo
foo.nim(17) foo
Error: unhandled exception: Second param 4 is not a float [CatchableError]
Run
Is it possible to write code that will catch the error at compilation time and
print a precise error message to the user (not the like of Error: type
mismatch: got <Real, int literal(4)> but expected one of ... 30 other
mismatching symbols have been suppressed)?