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)?

Reply via email to