Skip to content

Commit 9d90158

Browse files
authored
Merge pull request #223 from SpinnySpiwal/master
Enhance expressionPow to support unary operators on the right-hand side, preserving right-associativity. Added tests to validate the fix for precedence issues.
2 parents 728a837 + 5d46fa2 commit 9d90158

4 files changed

Lines changed: 135 additions & 13 deletions

File tree

src/prometheus/compiler/statements/for_statement.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ return function(self, statement, funcDepth)
6868

6969
local shouldSwap2 = math.random(1, 2) == 2;
7070
local shuffledRegs3 = shouldSwap2 and {currentReg, finalReg} or {finalReg, currentReg};
71-
self:addStatement(self:setRegister(scope, tmpReg2, Ast[shouldSwap2 and "LessThanOrEqualsExpression" or "GreaterThanOrEqualsExpression"](self:register(scope, shuffledRegs3[1]), self:register(scope, shuffledRegs3[2]))), {tmpReg2}, {shuffledRegs3[1], shuffledRegs3[2]}, false);
71+
self:addStatement(self:setRegister(scope, tmpReg2, Ast[shouldSwap2 and "GreaterThanOrEqualsExpression" or "LessThanOrEqualsExpression"](self:register(scope, shuffledRegs3[1]), self:register(scope, shuffledRegs3[2]))), {tmpReg2}, {shuffledRegs3[1], shuffledRegs3[2]}, false);
7272

7373
self:addStatement(self:setRegister(scope, tmpReg2, Ast.AndExpression(self:register(scope, incrementIsNegReg), self:register(scope, tmpReg2))), {tmpReg2}, {tmpReg2, incrementIsNegReg}, false);
7474
self:addStatement(self:setRegister(scope, tmpReg1, Ast.OrExpression(self:register(scope, tmpReg2), self:register(scope, tmpReg1))), {tmpReg1}, {tmpReg1, tmpReg2}, false);

src/prometheus/parser.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,8 @@ function Parser:expressionPow(scope)
716716
local lhs = self:tableOrFunctionLiteral(scope);
717717

718718
if(consume(self, TokenKind.Symbol, "^")) then
719-
local rhs = self:expressionPow(scope);
719+
-- Allow unary operators on the rhs (e.g. 2 ^ #x, 2 ^ -x) while preserving right-associativity. ~ SpinnySpiwal
720+
local rhs = self:expressionUnary(scope);
720721
return Ast.PowExpression(lhs, rhs, true);
721722
end
722723

tests/loops.lua

Lines changed: 112 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,116 @@
1-
-- This Test is Part of the Prometheus Obfuscator by Levno_710
2-
--
3-
-- loops.lua
4-
--
5-
-- This Test demonstrates a simple loop that creates a predictable sequence.
1+
--============================================================
2+
-- Iteration Test Suite
3+
-- Target: General purpose
4+
-- Author: SpinnySpiwal
5+
-- Purpose: Validate functionality of iterative loops.
6+
-- Note: this test was rewritten after discovering yet another bug in the compiler.
7+
-- The bug was with negative for statements not functioning. And it slipped past the tests.
8+
-- This test ensures this won't happen again.
9+
--============================================================
610

7-
local x = {};
8-
for i = 1, 100 do
9-
x[i] = i;
11+
local TESTS_PASSED = 0
12+
local byte, floor = string.byte, math.floor
13+
local x, y, z, w, t, expected = nil, nil, nil, nil, nil, nil
14+
local function round(value, precision)
15+
return floor(value * 10^precision) / 10^precision
1016
end
1117

12-
for i, v in ipairs(x) do
13-
print("x[" .. i .. "] = " .. v);
18+
local function str2num(str)
19+
local result = 0
20+
for i=1, #str, 1 do
21+
result = result + byte(str, i)
22+
end
23+
return result
1424
end
25+
--============================================================
26+
-- Test 1: Ascending for loop (integer)
27+
--============================================================
28+
y = 0
29+
for _=1, 100 do
30+
y = y + 1
31+
end
32+
33+
if y ~= 100 then
34+
print("TEST 1: Ascending for loop (integer) FAILED! Expected 100, got " .. y)
35+
else
36+
TESTS_PASSED = TESTS_PASSED + 1
37+
end
38+
39+
--============================================================
40+
-- Test 2: Descending for loop (integer)
41+
--============================================================
42+
z = 0
43+
for _=100, 1, -1 do
44+
z = z + 1
45+
end
46+
47+
if z ~= 100 then
48+
print("TEST 2: Descending for loop (integer) FAILED! Expected 100, got " .. z)
49+
else
50+
TESTS_PASSED = TESTS_PASSED + 1
51+
end
52+
53+
--============================================================
54+
-- Test 3: Ascending for loop (float)
55+
--============================================================
56+
w = 0
57+
for _=0, 100, 0.1 do
58+
w = w + 0.1
59+
end
60+
61+
if round(w, 1) ~= 100 then
62+
print("TEST 3: Ascending for loop (float) FAILED! Expected 100, got " .. round(w, 1))
63+
else
64+
TESTS_PASSED = TESTS_PASSED + 1
65+
end
66+
67+
--============================================================
68+
-- Test 4: Descending for loop (float)
69+
--============================================================
70+
w = 0
71+
for _=100, 0, -0.1 do
72+
w = w + 0.1
73+
end
74+
75+
if round(w, 1) ~= 100 then
76+
print("TEST 4: Descending for loop (float) FAILED! Expected 100, got " .. round(w, 1))
77+
else
78+
TESTS_PASSED = TESTS_PASSED + 1
79+
end
80+
81+
--============================================================
82+
-- Test 5: Table iteration (ipairs)
83+
--============================================================
84+
t = {1, 2, 3, 4, 5}
85+
x = 0
86+
expected = 20
87+
for _,v in ipairs(t) do
88+
x = x + (1+v)
89+
end
90+
91+
if x ~= expected then
92+
print("TEST 5: Table iteration (ipairs) FAILED! Expected 5, got " .. x)
93+
else
94+
TESTS_PASSED = TESTS_PASSED + 1
95+
end
96+
97+
--============================================================
98+
-- Test 6: Table iteration (pairs)
99+
-- Note: the test is written this way because the pairs function is not sequential.
100+
-- However, numbers when added together are always the same.
101+
--============================================================
102+
expected = 750
103+
t = {a = 1, b = 2, c = 3, d = 4, e = 5}
104+
y = 0
105+
106+
for k, v in pairs(t) do
107+
y = y + str2num(k .. v)
108+
end
109+
110+
if y ~= expected then
111+
print("TEST 6: Table iteration (pairs) FAILED! Expected " .. expected .. ", got " .. y)
112+
else
113+
TESTS_PASSED = TESTS_PASSED + 1
114+
end
115+
116+
print("TESTS PASSED: " .. TESTS_PASSED .. "/6")

tests/syntax.lua

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
-- Syntax Test Suite
33
-- Target: Unparser
44
-- Author: SpinnySpiwal
5-
-- Purpose: Validate appropriate unparser functionality, specifically in unseen edge cases.
5+
-- Purpose: Validate appropriate parser & unparser functionality, specifically in unseen edge cases.
6+
-- Update 1: Added test for precedence bug fix in expressionPow.
67
--============================================================
78

89
local char = ("").char
@@ -17,3 +18,21 @@ local ok = pcall(function(...)
1718
print("hello " .. ...)
1819
end)
1920
print(ok and "no" or "yes")
21+
22+
local function getString()
23+
return "this string is 24 chars!"
24+
end
25+
26+
-- Test for precedence bug fix in expressionPow
27+
if 2 ^ #getString() == 16777216 then
28+
print("TEST 1 PASSED")
29+
else
30+
print("TEST 1 FAILED")
31+
end
32+
33+
-- Check if it still works the other way around
34+
if (#getString()) ^ 2 == 576 then
35+
print("TEST 2 PASSED")
36+
else
37+
print("TEST 2 FAILED")
38+
end

0 commit comments

Comments
 (0)