[Closed] Getting Local variables names and values
It’s not marvelous as it’s only valid for local variables which hold values, not references…
… but it works for locals wich hold global structs with value parameters.
Thank’s to @Bobo for this thread: http://forums.cgsociety.org/showthread.php?t=820737
-- Example of global struct
struct theValue (value)
-- Function to get local Variables names and values
fn getLocalsNames =
(
ss = stringstream ""
with printAllElements true (stack to:ss)
vars = #()
seek ss 0
skipToString ss "[stack level: 1]
"
while (not eof ss) do
(
if (skipToString ss "Locals:
") != undefined then
(
theLine = readLine ss
theLine = trimLeft theLine "- "
do
(
colonPos = findString theLine ":"
varName = subString theLine 1 (colonPos-1)
varValue = (subString theLine (colonPos+1) -1)
if (subString varValue (varValue.count-1) -1) != "()" do -- Avoids functions (and converting local functions to global functions)
(
varValue = try (execute varValue) catch ("Can't cast__" + trimLeft (varValue))
append vars #(varName,varValue)
)
theLine = readLine ss
theLine = trimLeft theLine "- "
)
while (theLine != "Externals:") and (not eof ss)
)
else
(
seek ss (ss as string).count
)
)
vars
)
--/* Example
(
aaa = 7
ccc = "Hello World"
ddd = sphere()
addmodifier ddd (bend())
eee = ddd.modifiers
thearray = for i =1 to 100 collect i
fn gg x = x^2
fff = gg aaa
kkk = pi
ppp = theValue value:kkk
qqq = theValue [5,8,9]
www = theValue theArray
vars = getLocalsNames()
for v in vars do
(
format "Name: % ; Value= %
" v[1] v[2]
if (superClassOf v[2] == StructDef) do format " Struct Value= %
" v[2].value
)
ok
)
Of course, this allows with a little-easy parsing to get the ‘execute’ command work in local scope, by replacing the variable name with its value as string.
That’s not the hard part (execute (“blah bla” + var as string + “blah”) always works), the trouble with execute is using local functions and structs. And that it executes in global scope, so you cannot change variable contents (like sum += 1 if sum is a local variable) and you are limited to what’s returned in the end.
You need parsing (only valid for values, not references)
-- Get LocalVariable value as string
fn getLocalStringValue varName =
(
varName = varName + ":"
varLength = varName.count
ss = stringstream ""
with printAllElements true (stack to:ss)
varValue = undefined
seek ss 0
skipToString ss "[stack level: 1]
"
while (not eof ss) do
(
if (skipToString ss "Locals:
") != undefined then
(
theLine = readLine ss
while (((subString theLine 1 2) != "**") and (not eof ss)) do
(
start = trimLeft theLine "- "
if (substring start 1 varLength) == varName do
(
varValue = (subString start (varLength+1) -1)
varValue = try (execute varValue; varValue) catch ("undefined")
)
theLine = readLine ss
)
)
else
(
seek ss (ss as string).count
)
)
varValue
)
-- Parse expression to evaluate
fn parse expression wordToReplace varName =
(
varValue = getLocalStringValue varName
pos = findString expression wordToReplace
do
(
expression = replace expression pos wordToReplace.count varValue
pos = findString expression wordToReplace
) while pos != undefined
expression
)
-- Example
(
local myLocalVar1 = 1, myLocalVar2 = 2, myLocalVar3 = 3, myLocalVar4 = [1,2,3]
local varNames = #("myLocalVar1", "myLocalVar2", "myLocalVar3", "myLocalVar4")
expressionToEvaluate = "localVar * 100 + localVar*localVar"
for v in varNames do
(
expression = parse expressionToEvaluate "localVar" v
format "% ==> Expression Result= %
" v (execute expression)
)
ok
)
But it works for some cases…
fn globalFunction x = (x += 1)
(
local myLocalVar1 = 1
expressionToEvaluate = "globalFunction x"
for i = 1 to 10 do
(
expression = parse expressionToEvaluate "x" "myLocalVar1"
myLocalVar1 = execute expression
format "==> Expression Result= %
" myLocalVar1
)
ok
)
The only difference is the different way of getting variable name (not that I would ever change a variable name for something OUTSIDE the code):
-- Example
(
local myLocalVar1 = 1, myLocalVar2 = 2, myLocalVar3 = 3, myLocalVar4 = [1,2,3]
local variables = #(&myLocalVar1, &myLocalVar2, &myLocalVar3, &myLocalVar4)
fn insertVal &val = val as string + " * 100 + " + val as string + "*" + val as string
for i = 1 to variables.count do
(
expression = insertVal variables[i]
format "% ==> Expression Result= %
" variables[i] (execute expression)
)
ok
)
I think we’re talking about different things… I’m going to study your example deeper, but I think it’s not for the same purpose I have in mind.
Thanks for sharing it.
Yes. In fact it’s not the same.
That’s what I need and what I’ve got with my method (the use of a local of other scope only knowing its name):
struct myStruct
(
theValue,
fn applyExpressionToValue fnExpression =
(
LA = execute ("fn myFunction " + fnExpression)
result = LA theValue
)
)
(
myStructInstance = myStruct [1,2,3]
sp = 100
myStructInstance.applyExpressionToValue "x = x * 100" -- Works of course
--myStructInstance.applyExpressionToValue "x sp = x * sp" -- Doesn't works as function needs two arguments. But it's what I need
-- I don't want to pass sp to the struct. Just it's name inside the expression
)
But, as you said, it’s not a good practice to use/find a variable only by its name outside its scope, so I discarded this method some weeks ago.