
KeylessUniversal

-- SINGLE-LINE JS INTERPRETER WITH LIVE MODE & CLEARLL (evaluator fix)
local PREFIX = "js:"
local UNLOAD_KEY = Enum.KeyCode.M
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local player = Players.LocalPlayer
-- FULL UNLOAD OLD COPY
if _G.JSInterpreterLoaded then
if _G.JSUnloadFunc then _G.JSUnloadFunc() end
end
_G.JSInterpreterLoaded = true
-- Interpreter state
local codeBuffer = {}
local variables = {}
local functions = {}
local running = false
local enabled = true
local chatConn, inputConn
-- CONSOLE / CHAT API
local console = {}
local c = console
function console.log(msg)
print("[JS]", tostring(msg))
end
function console.chat(msg)
if ReplicatedStorage:FindFirstChild("DefaultChatSystemChatEvents") then
pcall(function()
ReplicatedStorage.DefaultChatSystemChatEvents.SayMessageRequest:FireServer(tostring(msg),"All")
end)
else
if player then
pcall(function() player:Chat(tostring(msg)) end)
else
warn("[JS] Cannot chat: player missing")
end
end
end
-- Random helper table (use m.r(min, max))
local m = {}
-- Random helper table (use m.r(min, max [, precision]))
local m = {}
-- seed once
if not _G.JSRandomSeeded then
local seed = (tick and tick() or os.time()) % 1e9
math.randomseed(seed)
math.random(); math.random(); math.random()
_G.JSRandomSeeded = true
end
-- Helper: round to N decimal places
local function roundTo(n, decimals)
local mult = 10 ^ (decimals or 0)
return math.floor(n * mult + 0.5) / mult
end
-- m.r(min, max [, precision])
-- - If both min and max are integer-like and precision is nil -> returns integer in [min,max]
-- - If precision is provided (non-negative integer) -> returns a number with that many decimals
-- * If precision == 0 behaves like integer mode
-- * If precision > 0 returns a float with exactly that many decimals (rounded)
-- - If precision is nil and either arg is non-integer -> returns a float with full math.random() precision
function m.r(minv, maxv, precision)
minv = tonumber(minv) or 0
maxv = tonumber(maxv) or 1
if minv > maxv then minv, maxv = maxv, minv end
-- If precision explicitly provided
if precision ~= nil then
precision = tonumber(precision) or 0
if precision <= 0 then
-- integer behavior
local imin = math.ceil(minv)
local imax = math.floor(maxv)
if imin > imax then return imin end
return math.random(imin, imax)
end
-- produce float with 'precision' decimal places
local scale = 10 ^ precision
-- choose integer in scaled range, but avoid exact endpoints if you want open interval
local scaledMin = math.ceil(minv * scale)
local scaledMax = math.floor(maxv * scale)
if scaledMin > scaledMax then
-- fallback: produce a single rounded value
return roundTo(minv, precision)
end
local r = math.random(scaledMin, scaledMax) / scale
return roundTo(r, precision)
end
-- No precision provided: previous behavior
if math.floor(minv) == minv and math.floor(maxv) == maxv then
return math.random(minv, maxv)
end
-- mixed/float args -> return float in [minv, maxv)
return minv + math.random() * (maxv - minv)
end
-- Strip comments and pasted metadata
local function stripComments(line)
if not line then return "" end
line = line:gsub("//.*", "")
line = line:gsub("#.*", "")
line = line:gsub("<WebsiteContent_[^>]->", "")
line = line:gsub("</WebsiteContent_[^>]->", "")
line = line:gsub("<[^>]->", "")
return line:match("^%s*(.-)%s*$") or ""
end
-- Enhanced syntax check
local function syntaxValid(line)
line = stripComments(line)
if line == "" then return false end
if line:match("^var%s+[%a_][%w_]*%s*=%s*.+") then return true end
if line:match("^[%a_][%w_]*%s*=%s*.+") then return true end
if line:match("^function%s+%w+%s*%((.-)%)%s*{.-}$") then return true end
if line:match("^console%.") or line:match("^c%.") then return true end
if line:match("^if%s*%(.+%)%s*{.-}%s*else%s*{.-}$") then return true end
if line:match("^if%s*%(.+%)%s*{.-}$") then return true end
if line:match("%f[%w]true%f[%W]") or line:match("%f[%w]false%f[%W]") then return true end
return false
end
-- Convert JS operators and boolean literals to Lua equivalents
local function convertMath(expr)
if not expr then return expr end
-- boolean literals
expr = expr:gsub("%f[%w]true%f[%W]","true")
expr = expr:gsub("%f[%w]false%f[%W]","false")
-- logical operators
expr = expr:gsub("&&"," and ")
expr = expr:gsub("%|%|"," or ")
expr = expr:gsub("!%s*","not ")
-- inequality
expr = expr:gsub("!=","~=")
-- exponent
expr = expr:gsub("%*%*","^")
return expr
end
-- Evaluate expression in sandboxed env that resolves names from variables first
local function evaluate(expr)
if expr == nil then return nil end
expr = expr:match("^%s*(.-)%s*$")
-- quoted boolean strings
local quoted = expr:match('^"(.-)"$') or expr:match("^'(.-)'$")
if quoted == "true" then return true end
if quoted == "false" then return false end
expr = convertMath(expr)
-- Build sandbox environment that resolves identifiers from variables table
local env = {}
env.math = math
env.string = string
env.tonumber = tonumber
env.tostring = tostring
env.pairs = pairs
env.ipairs = ipairs
env.print = print
env.m = m -- <--- expose the random helper
setmetatable(env, {
__index = function(_, k)
-- first check interpreter variables
if variables[k] ~= nil then return variables[k] end
-- then fallback to global
return _G[k]
end
})
-- try as expression first
local chunk, err = loadstring("return "..expr)
if not chunk then
-- try as statement
chunk, err = loadstring(expr)
end
if not chunk then
warn("[JS] Eval compile error:", err, "expr:", expr)
return nil
end
-- set environment and run
local ok, res
-- setfenv is available in Roblox Lua (5.1)
pcall(function() setfenv(chunk, env) end)
ok, res = pcall(chunk)
if not ok then
warn("[JS] Eval runtime error:", res, "expr:", expr)
return nil
end
return res
end
-- Assignment handler (supports "var name = value" and "name = value")
local function handleAssignment(line)
local name, value = line:match("^var%s+([%a_][%w_]*)%s*=%s*(.+)")
if not name then
name, value = line:match("^([%a_][%w_]*)%s*=%s*(.+)")
end
if name and value then
value = stripComments(value):match("^%s*(.-)%s*$")
local quoted = value:match('^"(.-)"$') or value:match("^'(.-)'$")
if quoted == "true" then variables[name] = true; return true end
if quoted == "false" then variables[name] = false; return true end
local ok, res = pcall(function() return evaluate(value) end)
if ok then variables[name] = res else warn("[JS] Assignment eval failed for "..name..":", res) end
return true
end
return false
end
-- Run a single line (supports nested single-line if/else)
local function runLine(line)
line = stripComments(line)
if line == "" then return end
-- assignment
if handleAssignment(line) then return end
-- function
if line:match("^function") then
local fname,args,body = line:match("^function%s+(%w+)%s*%((.-)%)%s*{(.-)}$")
if fname and args and body then
functions[fname] = {args=args, body=body}
end
return
end
-- if/else (supports single-line if without else)
if line:match("^if%s*%(") then
local cond, ifbody, elsebody
cond, ifbody, elsebody = line:match("^if%s*%((.-)%)%s*{(.-)}%s*else%s*{(.-)}")
if cond then
if evaluate(cond) then runLine(ifbody) else runLine(elsebody) end
return
end
cond, ifbody = line:match("^if%s*%((.-)%)%s*{(.-)}")
if cond then
if evaluate(cond) then runLine(ifbody) end
return
end
warn("[JS] Malformed if statement:", line)
return
end
-- function call resolution for user-defined functions
-- (simple inline replacement for single-line functions)
if line:match("(%w+)%s*%(") then
-- try to detect console calls first
if line:match("console%.log") or line:match("c%.l") then
local expr = line:match("console%.log%((.+)%)") or line:match("c%.l%((.+)%)")
if expr then console.log(evaluate(expr)) end
return
end
if line:match("console%.chat") or line:match("c%.c") then
local expr = line:match("console%.chat%((.+)%)") or line:match("c%.c%((.+)%)")
if expr then console.chat(evaluate(expr)) end
return
end
end
-- fallback: try to evaluate as expression/statement
local ok, res = pcall(function() return evaluate(line) end)
if not ok then warn("[JS] RunLine eval failed:", res) end
end
-- Execute program buffer
local function executeBuffer()
for _,line in ipairs(codeBuffer) do
local ok, err = pcall(function() runLine(line) end)
if not ok then warn("[JS] Error executing line:", line, err) end
end
end
-- Handle chat input
local function handleJSCommand(msg)
if not enabled then return end
if msg:sub(1,#PREFIX):lower() ~= PREFIX then return end
local code = msg:sub(#PREFIX+1):gsub("^%s+","")
-- COMMANDS
if code == "print" then
print("========== JS PROGRAM ==========")
for _,line in ipairs(codeBuffer) do print(line) end
print("========== END PROGRAM ==========")
return
elseif code == "clip" then
if setclipboard then
setclipboard(table.concat(codeBuffer,"\n"))
print("[JS] Program copied to clipboard!")
else
warn("[JS] Clipboard unavailable")
end
return
elseif code == "clear" then
codeBuffer = {}
variables = {}
functions = {}
print("[JS] Program cleared")
return
elseif code == "clearll" then
local last = table.remove(codeBuffer)
if last then
local varName = last:match("^var%s+(%w+)%s*=") or last:match("^([%a_][%w_]*)%s*=")
if varName then variables[varName] = nil end
local funcName = last:match("^function%s+(%w+)%s*%(")
if funcName then functions[funcName] = nil end
print("[JS] Last line cleared:", last)
else
print("[JS] No line to clear")
end
return
elseif code == "run" then
for _,line in ipairs(codeBuffer) do
if not syntaxValid(line) then
warn("[JS] Cannot run: Invalid code in buffer:", line)
return
end
end
running = true
executeBuffer()
print("[JS] Entered running mode — new JS executes instantly!")
return
elseif code == "stop" then
running = false
print("[JS] Stopped running code")
return
end
-- SINGLE-LINE STRICT CHECK
if not syntaxValid(code) then
warn("[JS] Invalid syntax:", code)
return
end
-- Add valid line to buffer
table.insert(codeBuffer, code)
-- Instantly execute if running
if running then
local ok, err = pcall(function() runLine(code) end)
if not ok then warn("[JS] Runtime error:", err) end
end
end
-- CHAT CONNECTION (Unified)
local ChatEvents = game:FindFirstChild("DefaultChatSystemChatEvents", true)
if ChatEvents and ChatEvents:IsA("Folder") and ChatEvents:FindFirstChild("OnMessageDoneFiltering") then
chatConn = ChatEvents.OnMessageDoneFiltering.OnClientEvent:Connect(function(msgData)
if msgData.Message and type(msgData.Message)=="string" then
handleJSCommand(msgData.Message)
end
end)
else
chatConn = player.Chatted:Connect(handleJSCommand)
end
-- UNLOAD
local function fullUnload()
enabled = false
codeBuffer = {}
variables = {}
functions = {}
if chatConn then chatConn:Disconnect() end
if inputConn then inputConn:Disconnect() end
_G.JSInterpreterLoaded = false
_G.JSUnloadFunc = nil
print("[JS] Fully Unloaded")
end
_G.JSUnloadFunc = fullUnload
inputConn = UserInputService.InputBegan:Connect(function(input,gp)
if gp then return end
if input.KeyCode == UNLOAD_KEY then fullUnload() end
end)
print("[JS] Loaded (evaluator fixed)")



sawdwad