Notifications
Clear all

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

9 Replies

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.

1 Reply
(@swordslayer)
Joined: 2 years ago

Posts: 0

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
		)
		

Ok. You’re right. It’s very limited.

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.