Page 1 of 2

Eval - Evaluate Expressions in Strings Dynamically (Updated Dec, 28, 2020)

Posted: 31 Jan 2016, 23:33
by Pulover
Array := Eval(String [, CustomVars])

This is my take on the Eval() function. The actual evaluation is done by Uberi's ExprEval(), but I've added parsers to support objects and ternary. There's also an optional parameter to set Custom Variables, mostly usable to resolve built-in variables like A_Index, A_LoopField, etc. Usage is explained in the header.

:arrow: Sources and examples on GitHub

Know limitation: Some short variable names used in the ExprEval() should be avoided as they will not be correctly evaluated. The names are a, e, i, o, r, s, t, ac, eo, lf, lp, tt and numbered variations of them like a1, a2... tt1, tt2....

Re: Eval - Evaluate Expressions in Strings

Posted: 01 Feb 2016, 12:59
by oldbrother
Is is possible to make "Eval" to interact with the main program?

Like this:

Code: Select all

#SingleInstance Force
#include Eval.ahk
SetBatchLines, -1

Var1 :=12
Var2 :=20

Expression := "Var1 * Var2"
Result := Eval(Expression)

MsgBox %Result%  ; currently not working
ExitApp

Edited!

Sorry, after I added StrJoin(), it worked. Thanks a lot!

Code: Select all

#SingleInstance Force
#include Eval.ahk
SetBatchLines, -1

Var1 :=12
Var2 := 24

Expression := "Var1 *Var2"
Result := Eval(Expression)

r := StrJoin(Result, "`n")
MsgBox, %r%

ExitApp

Re: Eval - Evaluate Expressions in Strings

Posted: 01 Feb 2016, 13:07
by Pulover
Hello oldbrother,

The output is an array, because you can evaluate multiple expressions (e.g. "Var1 * Var2, Var1 / Var2") so you have to select one to show.
To make your test work you can either do this:

Code: Select all

Result := Eval(Expression)[1]
...or this:

Code: Select all

MsgBox % Result[1]

Re: Eval - Evaluate Expressions in Strings

Posted: 01 Feb 2016, 13:12
by oldbrother
Thank you very much!

Re: Eval - Evaluate Expressions in Strings

Posted: 01 Feb 2016, 22:02
by Pulover
Update:
  • Fixed problem solving more than one object reference in the same expression.
  • Fixed problem concatenating object values and other values.

Re: Eval - Evaluate Expressions in Strings

Posted: 02 Feb 2016, 12:06
by oldbrother
Hi Pulover,

Is it possible to get the result form multiple line equations?

For example:

D :=1.5
L :=2
Pi :=3.14

Str = ( S := Pi * (D/2)**2
V := S * L
Weight := V * 0.3
)

And then use Eval to get the result of "Weight".

Thanks!

Re: Eval - Evaluate Expressions in Strings

Posted: 02 Feb 2016, 16:50
by Pulover
Hi oldbrother,

You can use Join, or StrReplace() to replace line breaks with commas. Only trouble is the limitation I mentioned above about variable names used in ExprEval(), I had to rename the ones in your example to make it work.

Code: Select all

xD :=1.5
xL :=2
Pi :=3.14

Str =
(Join,
xS := Pi * (xD/2)**2
xV := xS * xL
Weight := xV * 0.3
)

Eval(Str)
MsgBox % Eval("Weight")[1]
I tried to rename variables in Uberi's functions but it stopped working. I will try to change at least a few of them.

Edit: I used a function to test all possible alphabetical variable names from a to zzz and found that the only names that should be avoided are a, e, i, o, r, s, t, ac, eo, lf, lp, tt and numbered variations like a1, a2... tt1, tt2.... Replacing even one of them is difficult because of combinations and variations, so I won't touch that.

Re: Eval - Evaluate Expressions in Strings

Posted: 03 Feb 2016, 08:39
by Gio
The function works nicely, thank you for it :thumbup:

I have some questions:

1 - Uberi stated that ExprEval was 28x slower than actual expression evaluation in one of his examples. Are there any big practical advantages of using this method vs the ordinary expression method though? Can you please provide examples?

2 - Is this part of a bigger project? (a compiler os something like that)?

Best wishes.

Re: Eval - Evaluate Expressions in Strings

Posted: 03 Feb 2016, 09:19
by Pulover
Hi Gio,

I haven't made performance tests, but it works fast enough for my needs :) .
The one practical use for this function is provide a method to evaluate expressions dynamically, i.e. you can get results from copied text, user input, read files, etc. Without eval you cannot build something like a calculator, or the expression tester I posted above.

I made this function to use with the next version of my Macro Creator. The current version uses Laszlo's Eval, but it's limited to math expressions. When I first tried Uberi's, some years ago, for some reason I couldn't get it to work with my project (I probably did something wrong), but in the last weeks I was looking for a way to support 'real' expressions and gave it another try and it worked well, allowing me to support multiple statements for example (a || b, a && b...). I knew how to evaluate object calls in strings, so I tried to combine what I did in my ComInterface function for PMC to give it support for object creation and calls, as well as functions that return objects, such as StrSplit(). The last thing I did was find a way to support ternary, one of the requests from Uberi's original post. I haven't tested short-circuiting, though.

Regards.

Re: Eval - Evaluate Expressions in Strings

Posted: 03 Feb 2016, 09:29
by Gio
Ok, thanks for the explanation, those examples did sparkled some more ideas :thumbup:

Re: Eval - Evaluate Expressions in Strings

Posted: 03 Feb 2016, 14:39
by Pulover
Update:
  • Added support for Object references in [key, key] format.
I was forgetting that it's possible to assign and access multi-dimensional arrays that way... I updated the function to make it consistent with this feature.

Example:

Code: Select all

Expression = 
(Join,
Obj := []
Obj[1, "Pi"] := 3.141593
)

Eval(Expression)

MsgBox % Eval("Obj[1, ""Pi""]")[1]

Re: Eval - Evaluate Expressions in Strings

Posted: 06 Feb 2016, 22:03
by Pulover
Update:
  • Updated to resolve objects inside CustomVars values.

Re: Eval - Evaluate Expressions in Strings

Posted: 10 Feb 2016, 09:54
by Pulover
Update:
  • Fixed bug in ExprEval() when concatenating variables or numbers with a number.
I had fixed a few bugs in Uberi's function already, and I have found now that it cannot process expressions like Variable 1 or Variable 1.1. Took me some time to figure out the code, but I managed to solve the problem.

Re: Eval - Evaluate Expressions in Strings

Posted: 16 Mar 2016, 20:12
by Pulover
Update:
  • Added support for Unicode strings.
  • Added support for dynamic references of objects and functions.
  • Fixed various bugs with literal strings.
I found that ExprEval() cannot parse Unicode strings, so I added a workaround.
The function should be able to evaluate dynamic references now, such as fn := "StrLen", %fn%("some string") and similar, as well as object calls with them.

Re: Eval - Evaluate Expressions in Strings

Posted: 21 Mar 2016, 17:55
by Pulover
Update: v1.1.1
  • Fixed creating linear arrays not working with string or array elements.
My mistake this time... forgot to restore strings and other elements before creating linear arrays.

Re: Eval - Evaluate Expressions in Strings Dynamically (Updated 03/21/2016)

Posted: 21 Mar 2016, 20:19
by Pulover
Update: v1.1.2
  • Fixed bug when creating associative arrays with commas in values (such as arrays or function parameters).
Just found another problem (I do hope they all will be fixed some day...), this time with Associative Arrays. Something like person := {name: "John", surname: "Smith", age: 26, stats: [10,9,8.5,7,9.5,10]} would not work because of the commas in stats. Fixed now.

Re: Eval - Evaluate Expressions in Strings Dynamically (Updated 03/21/2016)

Posted: 24 Mar 2016, 20:21
by Pulover
Update: v1.1.3
  • Added support for missing parameters in function calls.

Re: Eval - Evaluate Expressions in Strings Dynamically (Updated 03/21/2016)

Posted: 01 Apr 2016, 11:30
by Pulover
Update: v1.1.4
  • Fixed bug in ExprEval() with hex numbers.

Update v1.1.5

Posted: 14 Apr 2016, 10:06
by Pulover
Update: v1.1.5
  • Fixed problem with setting false value to COM object parameters.

Update v1.1.6

Posted: 27 Apr 2016, 11:26
by Pulover
Update: v1.1.6
  • Fixed identical function or object calls in being executed only once.