I have read https://forum.nim-lang.org/t/3199 but I am still puzzled
my situation is, I need the #define part works like that in C/FreeBasic, so if
#define DOP_COLOR(col) HIWORD(col), LOWORD(col)
then the code to create array in FreeBasic
dim as short opcodes(...)=> { _
FL_DOP_COLOR ,DOP_COLOR(FL_RED), _
FL_DOP_LINE , _
}
is expanded to
dim as short opcodes(...)=> { _
FL_DOP_COLOR ,HIWORD(FL_RED), LOWORD(FL_RED), _
FL_DOP_LINE , _
}
My try is actually failed
template DOP_COLOR(col: untyped):untyped=
HIWORD(col), LOWORD(col)
Error: invalid indentation
thanks
Nim templates are hygienic and not plain text substitutions.
The output of a template must be valid Nim syntax, the most similar would be a tuple:
template DOP_COLOR(col: untyped):untyped=
(HIWORD(col), LOWORD(col))
sorry, I can't still grasp the idea
if emit is used, then how to use DOP_COLOR in nim code obviously,
{. emit: """
#define DOP_COLOR(col) HIWORD(col), LOWORD(col)
""" .}
var opcodes = [
FL_DOP_COLOR ,DOP_COLOR(FL_RED),
FL_DOP_LINE ,
]
says
undeclared identifier: 'DOP_COLOR'
the tuple solution
template DOP_COLOR(col: untyped):untyped=
(HIWORD(col), LOWORD(col))
var opcodes = [
FL_DOP_COLOR ,DOP_COLOR(FL_RED),
FL_DOP_LINE ,
]
says
Error: type mismatch: got <tuple of (WORD, WORD)> but expected 'FL_DATAOPCODE = enum'
you need the template.
do you need an array or a seq?
your template should probably return a seq then
in both cases you need to concat somehow dopColor with the other elemnts
var opcodes = @[FL..].concat(DOP_COLOR(FL_RED)).concat(@[FL..])
you can't generate a a, b as this is not a valid expression and you cant just put a tuple inside an array. that's limiting : sorry. however in this case it might be better, as its bit confusing to have one element visually expanding to two in [a, b, c]
if you need an array, i think you need another macro to concat two arrays on construction?
the code is not too long for me to replace all DOP_COLOR(sth) with HIWORD(sth), LOWORD(sth) by hand. But it is some long for concat thus the code will be a mess.
But to speak generaly, there is no something like #define A B directive in C, which only replace A with B literally, in nim, isn't? Yes, I know #define must be used carefully even in C, but I am seeking an elegant workaround in nim.
#define DOP_COLOR(col) HIWORD(col), LOWORD(col)
dim as short opcodes(...)=> { _
FL_DOP_COLOR ,DOP_COLOR(FL_RED), _
FL_DOP_LINE , _
FL_DOP_VERTEX, 0, 0, _
FL_DOP_VERTEX,10000,10000, _
FL_DOP_END , _
FL_DOP_COLOR ,DOP_COLOR(FL_GREEN), _
FL_DOP_LINE , _
FL_DOP_VERTEX, 0,10000, _
FL_DOP_VERTEX,10000, 0, _
FL_DOP_END , _
FL_DOP_COLOR ,DOP_COLOR(FL_BLUE), _
FL_DOP_LINE , _
FL_DOP_VERTEX, 0, 5000, _
FL_DOP_VERTEX,10000, 5000, _
FL_DOP_END , _
FL_DOP_COLOR ,DOP_COLOR(Fl_DARK_YELLOW), _
FL_DOP_POLYGON , _
FL_DOP_VERTEX, 1000, 1000, _
FL_DOP_VERTEX, 1000, 9000, _
FL_DOP_VERTEX, 9000, 9000, _
FL_DOP_VERTEX, 9000, 1000, _
FL_DOP_VERTEX, 1000, 1000, _
_ ' opposite direction = hole
FL_DOP_VERTEX, 1500, 1500, _
FL_DOP_VERTEX, 8500, 1500, _
FL_DOP_VERTEX, 8500, 8500, _
FL_DOP_VERTEX, 1500, 8500, _
FL_DOP_VERTEX, 1500, 1500, _
FL_DOP_END _
}
Technically you could hack something by having DOP_COLOR generate code as string and then using parseStmt to convert that string to code.
That's really hacking though. If you have a lot of statements it might be worthwhile to create your own mini declarative language and have a macro parse it.
I have done that for a JIT Assembler here