From 87e41cc4de8dc82999c0bd7e089d5be85e5908aa Mon Sep 17 00:00:00 2001 From: Wunder Wulfe <29297318+Wunder-Wulfe@users.noreply.github.com> Date: Wed, 5 Aug 2026 00:23:34 -0300 Subject: [PATCH] Feature: Enhanced Proxies * Fixed blacklist to use frontier patterns instead of the previous pattern matching structure, which would erroneously detect statements like `owner_velocity_forward()` due to `_for` satisfying the previous `[%s%p]for` match. Now matches against `%f[%a](for)%f[%A]` * Enables additional compilation mode, allowing use of local variables, if statements, and return statements * Provides alternative ways of computing proxies optimally, by re-using calculation results, or short circuit evaluations / early exits via if statements * Prohibits function declarations, loops, and modification of global variables for security/safety reasons. Modifying, assigning to, or creating globals will result in an error * Improved readability / structure of expressions.lua code * Moved repetitive code into functions, and simplified logic * Additional logic moved into functions to make iteration and testing easier --- lua/pac3/libraries/expression.lua | 109 +++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 18 deletions(-) diff --git a/lua/pac3/libraries/expression.lua b/lua/pac3/libraries/expression.lua index f44ad9655..216fd137d 100644 --- a/lua/pac3/libraries/expression.lua +++ b/lua/pac3/libraries/expression.lua @@ -1,4 +1,3 @@ - local lib = { PI = math.pi, rand = math.random, @@ -37,34 +36,108 @@ local lib = { round = math.Round, } -local blacklist = {"repeat", "until", "function", "end"} +local blacklist = { + "function"; + "for"; "break"; + "while"; "do"; + "repeat"; "until"; +} -local function compile_expression(str, extra_lib) - for _, word in pairs(blacklist) do - if str:find("[%p%s]" .. word) or str:find(word .. "[%p%s]") then - return false, string.format("illegal characters used %q", word) +-- convert blacklist items into patterns to match +for k, item in pairs(blacklist) do + -- uses more efficient / conclusive frontier pattern syntax + -- frontier matches transition into and out of sets + -- in this case, matching transition into letters and then out of letters (to match whole words and not partials) + blacklist[k] = ("%%f[%%a](%s)%%f[%%A]"):format(item) +end + +local function_intro = "local IN = (...); " + +local function_formats = { + function_intro .. "return %s"; + function_intro .. "%s"; -- allows return semantics +} + +local function TryCompile(code, identifier) + local result = CompileString(code, identifier, false) + + return not isstring(result), result +end + +local function CompileStringAdvanced(code, identifier) + local success, func = false, nil + + for _, structure in pairs(function_formats) do + success, func = TryCompile(structure:format(code), identifier) + + if success then break end + end + + return success, func +end + +local function readonlyError() + error("Not allowed to assign to globals", 2) +end + +local function makeReadonly(t) + return setmetatable( + {}, + { + __index = t, + __newindex = readonlyError, + __metatable = "This metatable is locked." + } + ) +end + +local function copyInto(t1, t2) + for k,v in pairs(t1) do t2[k] = v end +end + +local function checkBlacklist(code) + local str + + for _, word in pairs(blacklist) do + str = code:match(word) + + if str then + return str end end + + return nil +end - local functions = {} +local function compile_expression(str, extra_lib) + local illegalWord = checkBlacklist(str) + + if illegalWord then + return false, string.format("illegal characters used %q", illegalWord) + end - for k,v in pairs(lib) do functions[k] = v end + local success, func = CompileStringAdvanced(str, "pac_expression") - if extra_lib then - for k,v in pairs(extra_lib) do functions[k] = v end - end + if success then + local functions = {} - functions.select = select - str = "local IN = select(1, ...) return " .. str + copyInto(lib, functions) - local func = CompileString(str, "pac_expression", false) + if extra_lib then + copyInto(extra_lib, functions) + end - if isstring(func) then - return false, func - else - setfenv(func, functions) + functions.select = select + + setfenv( + func, + makeReadonly(functions) + ) + return true, func end + + return false, func end return compile_expression