I'm using Nim type system and templates to build a table of allowed types in a DSL language, like the following:
template final_sort2(v: bool): typedesc =
AST_bool
template final_sort2(v: int): typedesc =
AST_int
...
template final_sort2(v: typed): typedesc =
{.line: instantiationInfo().}:
raise newException(Exception, "Incompatible type: " & $v)
How can I have the compiler raise the exception when the last template is selected?
The code works without that last template, but the error message and the stack trace reported by the compiler does not help the developer understand the reason of the problem.
Error: in expression 'final_sort(b)(ite`gensym19185006)': identifier expected, but found 'final_sort(b)'
I would rather have a specific message reported when I can.
Replying myself to my question.
Even if the flow of control is supposed to stop because of the exception, as the template is declared to return a typedesc, the last instruction must be a typedesc else the compiler prints another error... So to get the expected behaviour, the correct last template is now:
template final_sort2(v: typed): typedesc =
raise newException(Exception, "Incompatible type: " & $v)
AST_null
You should also be able to do
template final_sort2(v: typed) =
raise newException(Exception, "Incompatible type: " & $v)
Because type overloading does not include return types
Other option, with compile time errors:
import macros
template final_sort2(v: bool): int = 3
macro final_sort2(v: typed): int =
error("Incompatible type: " & repr(getTypeInst(v)), v)
echo final_sort2(true)
echo final_sort2("hi") # Error: Incompatible type: string
Well, I did try @jyapayne proposal, because the less code the less bugs, but it did not work in my case. The error message Error: in expression 'final_sort2(b)(ite``gensym19335006)'... occurs at the call site of final_sort2 and not the exception. It's perhaps related to the fact that the returned typedesc is being used to do a conversion by the compiler.
In the end, I reverted back to returning a typedesc to please the compiler, and then the exception occurs.
For the moment, I'm using Nim type system to check acceptable types in the DSL, creating templates for the final_sort2 function: Nim type --> resulting DSL type. In the end, as the number of types will increase, I'll need a more flexible type checking system and I'll have to build a real table...
I would argue erroring at compile time instead of bothering with a runtime exception is "less code". You don't even have to use a macro, you can just use the error pragma. I don't know why I gave a macro.
template final_sort2(v: bool): typedesc = bool
template final_sort2(v: typed) =
{.error: "Incompatible type: " & $typeof(v).} # Error: Incompatible type: string
echo final_sort2(true)
echo final_sort2("hi") # template/generic instantiation of `final_sort2` from here
I would say this is as good as anything in regards to line/column information if you dont want to write a tiny macro, but it's your call