The way of Python's eval() in Lua

Preface

There’s a extremly function in Python which can calculate 1+3 without parsing. The function is:

eval()

I wrote this post for introducing you guys how to do the same things like eval() in Lua. Actually it is really simple.

Let’s Begin

Where did I get this issue?

Description

Actually, this issue came out when I want to calculate the numbers dynamically.

Define dynamically.

I have the following number, which is “8, 7, 6, 5, 4”. You can change the sequences as you want.(Let’s not make changes in sequence.)

For example, I want to do the following calculations below:

8 + 7 + 6 + 5 + 4

Also, I need this:

8 - 7 - 6 - 5 - 4

And this one:

8 x 7 + 6 / 5 - 4

Actually, there’re so many possibilities in here. But all you need is that you inject the operators into the arithmetic expressions.

More importantly, you may need more than that 4 operators, including “+ - × ÷“”. You may also have to use like “^ += and etc.“.

In extreme case, you may have to calcaulate the following expression:

i = i + k(k ≥ 1)

Therefore, it’s IMPOSSIBLE to use static way to calculate that.

A Little Summary of The Issue

  1. Input

    8 7 6 5 4

  2. Output

    A number

  3. Requirements

    • Don’t change the sequence
    • Inject the operators

Solution

Perfect Solution

This post is only to tell you how to do that by loadstring. Of course, you can use the Lunatic Python, which allows you use Python in your Lua.

You can do that by run python.eval() without any obstacle.

However, I have a heart that stricts of working styles without passing it(Actually just because I don’t like Python).

loadstring()

Click me to check the document

It’s pretty easy for you to make it happen, with some little misleading part.

Please check the following example:

1
2
3
4
5
6
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org, PUC-Rio
> a = '3'
> b = '7'
> operator = '+'
> loadstring("return ".. a .. operator .. b)()
10 -- Not even a decimal point

According to the calculations above you are able to do what we want.

How to do that exactly:

  1. Store your numbers into table in Lua
  2. Store your operaotors into a table
  3. Use for loop to calculate

Misleading part

Some Tests

You can get a different result if you do it accidentally. Here I am to introduce you to that.

Before I get the right code, I’ve suffered a lot. Here’s the test:

1
2
3
4
5
6
7
8
9
10
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org, PUC-Rio
> a = '3'
> b = '7'
> operator = '+'
> loadstring("return a" .. operator .. "b")()
10.0 -- A decimal point here
> loadstring("return 3" .. operator .. "7")()
10 -- No decimal point
> loadstring("return ".. a .. operator .. b)()
10 -- Also no decimal point

Why???
Because "return a" and "return " .. a are really different, including b's.

Why is that?? What happened?
I went to Stack Overflow to ask about this. Their saying is quite vague. Let me test that for you:

“ADP” is for “Has a decimal point”.
“NADP” is for “Doens’t have a decimal point”.
“aIN” is for “a in double quotation marks”.
“aNIN” is for “a not in double quotation marks”.
“bIN” is for “b in double quotation marks”.
“bNIN” is for “b not in double quotation marks”.
“abIN” is for “both of a and b not in double quotation marks”.
“abNIN” is for “neither of a and b not in double quotation marks”.
“3IN” is for “3 in double quotation marks”.
“3NIN” is for “3 not in double quotation marks”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
> a = '3'
> b = '7'
> operator = '+'
-- Group 1:a in double quotation marks
> loadstring("return a" .. operator .. "b")()
10.0 -- ADP, abIN
> loadstring("return a" .. operator .. b)()
10.0 -- ADP, aIN, bNIN
> loadstring("return a" .. operator .. 7)()
10.0 -- ADP, aIN, 7NIN
> loadstring("return a" .. operator .. "7")()
10.0 -- ADP, aIN, 7IN
-- Group 2:a not in double quotation marks
> loadstring("return " .. a .. operator.."7")()
10 -- DADP, aNIN, 7IN
> loadstring("return " .. a .. operator.. 7)()
10 -- DADP, aNIN, 7NIN
> loadstring("return " .. a .. operator .. "b")()
10.0 -- ADP, aNIN, bIN
> loadstring("return ".. a .. operator .. b)()
10 -- DADP, aNIN, bNIN
-- Group 3: not a and b, only numbers
> loadstring("return 3" .. operator .. "7")()
10 -- DADP, 3IN, 7IN
> loadstring("return 3" .. operator .. 7)()
10 -- DADP, 3IN, 7NIN
> loadstring("return " .. 3 .. operator .. 7)()
10 -- DADP, 3IN, 7NIN
> loadstring("return " .. 3 .. operator .. "7")()
10 -- DADP, 3NIN, 7IN

The Summary of Tests

  1. Group 1: No mather how the operands change, the result, which is float type data, has a decimal point in it when a is in double quotation marks.
    You are calculating an expression on STRINGS (strings implicitly get converted to floating point numbers). So, the result will get converted to floating point numbers with the latter operands and the operator. (Click me to know more about the rules)

  2. Group 2: There’s no more decimal point existed only the type of the latter is number when a is not in double quotation marks.
    Notice: although .. is for you to joint the strings or others, the result after using .. is string only. But before the conjunction, b is string-type number while 7 is number-type number.
    THEY ARE DIFFERENT!!

  3. Group 3: You can see that the result doesn’t have any decimal point without a and b.

Summary:

If a OR b are not included by a double quotation marks, both of operands will be converted to integer number;
if not, both of operands are considered as string-type number to take apart in the calculation, which is return stringA + number. The result must be converted to floating point numbers.

Concluding:

You may want to try the following codes:

1
2
3
loadstring("return " .. a .. operator .. b)()
-- OR
loadstring("return tonumber(a)"..operator.."tonumber(b)")()

End

Actually it’s really simple to understand. If you don’t, you may want to review the basic of Lua or try to read this post again.

Leave comments below if you have any questions.

End

0%