I'm looking for a way to test if a variable / expression is static, but from a macro (having only its name as a string), before codegen (i need this information to influence codegen).
I know i could do this in normal code:
assert foo(123) is static == true
And in other cases i could generate this code from the macro. But in the case of Nimja i think this does not work:
Nimja:
proc render(): string =
const foo = "foo"
compileTemplateStr """123{{foo}}456"""
is currently expanded to 3 result.add calls.
but since foo is a static var, two can be omitted:
i hope this will increase runtime performance even more.
The code flow through nimja:
in the step of FSNodes to NwtNode transformation, i have code like this:
# Simple Types
of FsStr:
pos.inc
## fsToken.value this is a str like "123" or "456"
return NwtNode(kind: NStr, strBody: fsToken.value)
of FsVariable:
pos.inc
## fsToken.value is the name of a variable like in the above "foo"
return NwtNode(kind: NVariable, variableBody: fsToken.value)
i need to test if fsToken.value of FsVariable is a static, so that i can generate strings instead of variables:
of FsVariable:
pos.inc
if expressionIsStatic(fsToken.value): ## how can i implement `expressionIsStatic`?
return NwtNode(kind: NStr, strBody: fsToken.value)
else:
return NwtNode(kind: NVariable, variableBody: fsToken.value)
you mean like this?
proc isConst(a: auto): bool =
return false
proc isConst(a: auto{lit|`const`}): bool =
return true
const
constant = "abc"
var
variable = "xyz"
proc myproc(): int = return 123
proc myproc(ii: int): int = return ii
echo isConst("literal")
echo isConst(constant)
echo isConst(variable)
# echo isConst(myproc) ## this should also be false
# echo isConst(myproc(123)) ## this should also be false, how?
Something like this also works:
proc isConst[T](a: T): bool =
false
proc isConst[T](a: static[T]): bool =
true
const
constant = "abc"
var
variable = "xyz"
proc myproc(): int = return 123
proc myproc(ii: int): int = return ii
echo isConst("literal")
echo isConst(constant)
echo isConst(variable)
echo isConst(myproc()) ## this should also be true
echo isConst(myproc(123)) ## this should also be true
var ii = 123
echo isConst(myproc(ii)) ## this should be false
Yes this gives the same results as the is static test.
isConst("literal")=true "literal" is static=true
isConst(constant)=true constant is static=true
isConst(variable)=false variable is static=false
isConst(myproc())=true myproc() is static=true
isConst(myproc(123))=true myproc(123) is static=true
isConst(myproc(ii))=false myproc(ii) is static=false
Now the next question arises, how could i do this in a macro?
const
constant = "abc"
macro mymacro() =
var varname = "constant"
var varlit = ident(varname) # ??? no
if isConst(varlit): # ??? no
echo varlit, " is const"
else:
echo varlit, " NOT const"
mymacro()
Now the next question arises, how could i do this in a macro?
I would say in general this is not possible. You generate code for which the meaning of said code depends on the place where the code will be inserted. The identifier may refer to a CT or RT variable, that's impossible to know.
Unfortunately, I don't really understand your explicit use case / under what conditions the code is used and how you need to detect that to offer some possible work arounds.
import macros
const constant = "abc"
macro mymacro(hasResult: static[bool] = false, isConst: static[bool] = false; idt: typed = nil): untyped =
if hasResult:
if isConst:
echo idt.strVal, " is const"
else:
echo idt.strVal, " NOT const"
else:
var varname = "constant"
var varlit = ident(varname)
result = quote do:
mymacro(hasResult=true, isConst=(`varlit` is static), `varlit`)
mymacro()