Advertisement
Guest User

Untitled

a guest
Oct 14th, 2019
1,544
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 304.54 KB | None | 0 0
  1. <roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
  2. <Meta name="ExplicitAutoJoints">true</Meta>
  3. <External>null</External>
  4. <External>nil</External>
  5. <Item class="ModuleScript" referent="RBX368AFF5C67F045749198DD239F0720E5">
  6. <Properties>
  7. <Content name="LinkedSource"><null></null></Content>
  8. <string name="Name">CmdrClient</string>
  9. <string name="ScriptGuid">{2396E93D-6873-4D5D-B171-B5778E9572D0}</string>
  10. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  11. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  12. -- @source https://github.com/evaera/Cmdr
  13. -- @rostrap Cmdr
  14. -- @author evaera
  15.  
  16. local RunService = game:GetService("RunService")
  17. local StarterGui = game:GetService("StarterGui")
  18. local Players = game:GetService("Players")
  19. local Player = Players.LocalPlayer
  20. local Shared = script:WaitForChild("Shared")
  21. local Util = require(Shared:WaitForChild("Util"))
  22. local Loadstring = require(script:WaitForChild('Loadstring'))
  23.  
  24. local Cmdr do
  25. Cmdr = setmetatable({
  26. ReplicatedRoot = script;
  27. RemoteFunction = Instance.new('BindableFunction');
  28. RemoteEvent = Instance.new('BindableEvent');
  29. ActivationKeys = {[Enum.KeyCode.Semicolon] = true};
  30. Enabled = true;
  31. MashToEnable = false;
  32. ActivationUnlocksMouse = true;
  33. PlaceName = "Cmdr";
  34. Util = Util;
  35. Events = {};
  36.  
  37. Loadstring = Loadstring
  38. }, {
  39. -- This sucks, and may be redone or removed
  40. -- Proxies dispatch methods on to main Cmdr object
  41. __index = function (self, k)
  42. local r = self.Dispatcher[k]
  43. if r and type(r) == "function" then
  44. return function (_, ...)
  45. return r(self.Dispatcher, ...)
  46. end
  47. end
  48. end
  49. })
  50.  
  51. Cmdr.Registry = require(Shared.Registry)(Cmdr)
  52. Cmdr.Dispatcher = require(Shared.Dispatcher)(Cmdr)
  53. end
  54.  
  55. require(script.CreateGui)()
  56. local Interface = require(script.CmdrInterface)(Cmdr)
  57.  
  58. --- Sets a list of keyboard keys (Enum.KeyCode) that can be used to open the commands menu
  59. function Cmdr:SetActivationKeys (keysArray)
  60. self.ActivationKeys = Util.MakeDictionary(keysArray)
  61. end
  62.  
  63. --- Sets the place name label on the interface
  64. function Cmdr:SetPlaceName (name)
  65. self.PlaceName = name
  66. Interface.Window:UpdateLabel()
  67. end
  68.  
  69. --- Sets whether or not the console is enabled
  70. function Cmdr:SetEnabled (enabled)
  71. self.Enabled = enabled
  72. end
  73.  
  74. --- Sets if activation will free the mouse.
  75. function Cmdr:SetActivationUnlocksMouse (enabled)
  76. self.ActivationUnlocksMouse = enabled
  77. end
  78.  
  79. --- Shows Cmdr window
  80. function Cmdr:Show ()
  81. if not self.Enabled then
  82. return
  83. end
  84.  
  85. Interface.Window:Show()
  86. end
  87.  
  88. --- Hides Cmdr window
  89. function Cmdr:Hide ()
  90. Interface.Window:Hide()
  91. end
  92.  
  93. --- Toggles Cmdr window
  94. function Cmdr:Toggle ()
  95. if not self.Enabled then
  96. return self:Hide()
  97. end
  98.  
  99. Interface.Window:SetVisible(not Interface.Window:IsVisible())
  100. end
  101.  
  102. --- Enables the "Mash to open" feature
  103. function Cmdr:SetMashToEnable(isEnabled)
  104. self.MashToEnable = isEnabled
  105.  
  106. if isEnabled then
  107. self:SetEnabled(false)
  108. end
  109. end
  110.  
  111. --- Sets the handler for a certain event type
  112. function Cmdr:HandleEvent(name, callback)
  113. self.Events[name] = callback
  114. end
  115.  
  116. -- Only register when we aren't in studio because don't want to overwrite what the server portion did
  117.  
  118. Cmdr.Registry:RegisterTypesIn(script:WaitForChild("Types"))
  119.  
  120. local Cmds = script:WaitForChild("Commands")
  121. for i,v in pairs(Cmds:GetChildren()) do
  122. if v:IsA('ModuleScript') then
  123. if require(v)() then
  124. Cmdr.Registry:RegisterCommandsIn(v)
  125. end
  126. else
  127. Cmdr.Registry:RegisterCommandsIn(v)
  128. end
  129. end
  130.  
  131. Player.Chatted:Connect(function(msg)
  132. if msg:sub(1,2) == '--' then
  133. Cmdr.Dispatcher:EvaluateAndRun(msg:sub(3), Player)
  134. end
  135. end)
  136.  
  137. -- Hook up event listener
  138. Cmdr.RemoteEvent.Event:Connect(function(name, ...)
  139. if Cmdr.Events[name] then
  140. Cmdr.Events[name](...)
  141. end
  142. end)
  143.  
  144. require(script.DefaultEventHandlers)(Cmdr)
  145.  
  146. return Cmdr]]></ProtectedString>
  147. <BinaryString name="Tags"></BinaryString>
  148. </Properties>
  149. <Item class="ModuleScript" referent="RBX8EDF08B92E914B60BDE7F1DD43F8D97E">
  150. <Properties>
  151. <Content name="LinkedSource"><null></null></Content>
  152. <string name="Name">DefaultEventHandlers</string>
  153. <string name="ScriptGuid">{235F4510-3809-4E94-99F5-E7D5EF9E85AF}</string>
  154. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  155. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  156. -- @source https://github.com/evaera/Cmdr
  157. -- @rostrap Cmdr
  158. -- @author evaera
  159.  
  160. local StarterGui = game:GetService("StarterGui")
  161. local Window = require(script.Parent.CmdrInterface.Window)
  162.  
  163. return function (Cmdr)
  164. Cmdr:HandleEvent("Message", function (text)
  165. StarterGui:SetCore("ChatMakeSystemMessage", {
  166. Text = ("[Announcement] %s"):format(text);
  167. Color = Color3.fromRGB(249, 217, 56);
  168. })
  169. end)
  170.  
  171. Cmdr:HandleEvent("AddLine", function (...)
  172. Window:AddLine(...)
  173. end)
  174. end]]></ProtectedString>
  175. <BinaryString name="Tags"></BinaryString>
  176. </Properties>
  177. </Item>
  178. <Item class="ModuleScript" referent="RBX326A7781248546519AAD866FC9257B72">
  179. <Properties>
  180. <Content name="LinkedSource"><null></null></Content>
  181. <string name="Name">CmdrInterface</string>
  182. <string name="ScriptGuid">{7E21D3D2-A7E4-4D31-9C6D-63FCF89BBB81}</string>
  183. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  184. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  185. -- @source https://github.com/evaera/Cmdr
  186. -- @rostrap Cmdr
  187. -- @author evaera
  188.  
  189. -- Here be dragons
  190.  
  191. local Players = game:GetService("Players")
  192. local Player = Players.LocalPlayer
  193.  
  194. return function (Cmdr)
  195. local Util = Cmdr.Util
  196.  
  197. local Window = require(script:WaitForChild("Window"))
  198. Window.Cmdr = Cmdr
  199.  
  200. local AutoComplete = require(script:WaitForChild("AutoComplete"))(Cmdr)
  201. Window.AutoComplete = AutoComplete
  202.  
  203.  
  204. -- Sets the Window.ProcessEntry callback so that we can dispatch our commands out
  205. function Window.ProcessEntry(text)
  206. text = Util.TrimString(text)
  207.  
  208. if #text == 0 then return end
  209.  
  210. Window:AddLine(Window:GetLabel() .. " " .. text, Color3.fromRGB(255, 223, 93))
  211.  
  212. Window:AddLine(Cmdr.Dispatcher:EvaluateAndRun(text, Player, {
  213. IsHuman = true
  214. }))
  215. end
  216.  
  217. -- Sets the Window.OnTextChanged callback so we can update the auto complete
  218. function Window.OnTextChanged (text)
  219. local command = Cmdr.Dispatcher:Evaluate(text, Player, true)
  220. local arguments = Util.SplitString(text)
  221. local commandText = table.remove(arguments, 1)
  222. local atEnd = false
  223. if command then
  224. arguments = Util.MashExcessArguments(arguments, #command.Object.Args)
  225.  
  226. atEnd = #arguments == #command.Object.Args
  227. end
  228.  
  229. local entryComplete = commandText and #arguments > 0
  230.  
  231. if text:sub(#text, #text):match("%s") and not atEnd then
  232. entryComplete = true
  233. arguments[#arguments + 1] = ""
  234. end
  235.  
  236. if command and entryComplete then
  237. local commandValid, errorText = command:Validate()
  238.  
  239. Window:SetIsValidInput(commandValid, ("Validation errors: %s"):format(errorText or ""))
  240.  
  241. local acItems = {}
  242.  
  243. local lastArgument = command:GetArgument(#arguments)
  244. if lastArgument then
  245. local typedText = lastArgument.RawSegments[#lastArgument.RawSegments]
  246. local items = lastArgument:GetAutocomplete()
  247. for i, item in pairs(items) do
  248. acItems[i] = {typedText, item}
  249. end
  250.  
  251. local valid = true
  252.  
  253. if #typedText > 0 then
  254. valid, errorText = lastArgument:Validate()
  255. end
  256.  
  257. return AutoComplete:Show(acItems, {
  258. at = atEnd and #text - #typedText + (text:sub(#text, #text):match("%s") and -1 or 0);
  259. prefix = #lastArgument.RawSegments == 1 and lastArgument.Prefix or "";
  260. isLast = #command.Arguments == #command.ArgumentDefinitions and #typedText > 0;
  261. numArgs = #arguments;
  262. command = command;
  263. arg = lastArgument;
  264. name = lastArgument.Name .. (lastArgument.Required and "" or "?");
  265. type = lastArgument.Type.DisplayName;
  266. description = (valid == false and errorText) or lastArgument.Object.Description;
  267. invalid = not valid;
  268. })
  269. end
  270. elseif commandText and #arguments == 0 then
  271. Window:SetIsValidInput(true)
  272. local exactCommand = Cmdr.Registry:GetCommand(commandText)
  273. local exactMatch
  274. if exactCommand then
  275. exactMatch = {exactCommand.Name, exactCommand.Name, options = {
  276. name = exactCommand.Name;
  277. description = exactCommand.Description;
  278. }}
  279. end
  280.  
  281. local acItems = {exactMatch}
  282. for _, cmd in pairs(Cmdr.Registry:GetCommandsAsStrings()) do
  283. if commandText:lower() == cmd:lower():sub(1, #commandText) and (exactMatch == nil or exactMatch[1] ~= commandText) then
  284. local commandObject = Cmdr.Registry:GetCommand(cmd)
  285. acItems[#acItems + 1] = {commandText, cmd, options = {
  286. name = commandObject.Name;
  287. description = commandObject.Description;
  288. }}
  289. end
  290. end
  291.  
  292. return AutoComplete:Show(acItems)
  293. end
  294.  
  295. Window:SetIsValidInput(false, "Invalid command. Use the help command to see all available commands.")
  296. AutoComplete:Hide()
  297. end
  298.  
  299. Window:UpdateLabel()
  300. Window:UpdateWindowHeight()
  301.  
  302. return {
  303. Window = Window;
  304. AutoComplete = AutoComplete;
  305. }
  306. end
  307. ]]></ProtectedString>
  308. <BinaryString name="Tags"></BinaryString>
  309. </Properties>
  310. <Item class="ModuleScript" referent="RBX240D210F33274C2EB2EA753E4EDE69C9">
  311. <Properties>
  312. <Content name="LinkedSource"><null></null></Content>
  313. <string name="Name">AutoComplete</string>
  314. <string name="ScriptGuid">{E9F50325-6C3B-45B6-BDF0-44C5C331798A}</string>
  315. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  316. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  317. -- @source https://github.com/evaera/Cmdr
  318. -- @rostrap Cmdr
  319. -- @author evaera
  320.  
  321. -- luacheck: ignore 212
  322. local Players = game:GetService("Players")
  323. local Player = Players.LocalPlayer
  324.  
  325. return function (Cmdr)
  326. local AutoComplete = {
  327. Items = {};
  328. ItemOptions = {};
  329. SelectedItem = 0;
  330. }
  331.  
  332. local Util = Cmdr.Util
  333. local Shorthands = Util.MakeDictionary({"me", "all", ".", "*", "others"})
  334.  
  335. local Gui = Player:WaitForChild("PlayerGui"):WaitForChild("Cmdr"):WaitForChild("Autocomplete")
  336. local AutoItem = Gui:WaitForChild("TextButton")
  337. local Title = Gui:WaitForChild("Title")
  338. local Description = Gui:WaitForChild("Description")
  339. local Entry = Gui.Parent:WaitForChild("Frame"):WaitForChild("Entry")
  340. AutoItem.Parent = nil
  341.  
  342. -- Helper function that sets text and resizes labels
  343. local function SetText(obj, textObj, text, sizeFromContents)
  344. obj.Visible = text ~= nil
  345. textObj.Text = text or ""
  346.  
  347. if sizeFromContents then
  348. textObj.Size = UDim2.new(0, Util.GetTextSize(text or "", textObj, Vector2.new(1000, 1000), 1, 0).X, obj.Size.Y.Scale, obj.Size.Y.Offset)
  349. end
  350. end
  351.  
  352. -- Update the info display (Name, type, and description) based on given options.
  353. local function UpdateInfoDisplay (options)
  354. -- Update the objects' text and sizes
  355. SetText(Title, Title.Field, options.name, true)
  356. SetText(Title.Field.Type, Title.Field.Type, options.type and ": " .. options.type:sub(1, 1):upper() .. options.type:sub(2))
  357. SetText(Description, Description.Label, options.description)
  358.  
  359. Description.Label.TextColor3 = options.invalid and Color3.fromRGB(255, 73, 73) or Color3.fromRGB(255, 255, 255)
  360.  
  361. -- Calculate needed width and height
  362. local infoWidth = Title.Field.TextBounds.X + Title.Field.Type.TextBounds.X
  363.  
  364. local guiWidth = math.max(infoWidth, Gui.Size.X.Offset)
  365. Description.Size = UDim2.new(1, 0, 0, 40)
  366.  
  367. -- Flow description text
  368. while not Description.Label.TextFits do
  369. Description.Size = Description.Size + UDim2.new(0, 0, 0, 2)
  370.  
  371. if Description.Size.Y.Offset > 500 then
  372. break
  373. end
  374. end
  375.  
  376. -- Update container
  377. wait()
  378. Gui.UIListLayout:ApplyLayout()
  379. Gui.Size = UDim2.new(0, guiWidth, 0, Gui.UIListLayout.AbsoluteContentSize.Y)
  380. end
  381.  
  382. --- Shows the auto complete menu with the given list and possible options
  383. -- item = {typedText, suggestedText, options?=options}
  384. -- The options table is optional. `at` should only be passed into AutoComplete::Show
  385. -- name, type, and description may be passed in an options dictionary inside the items as well
  386. -- options.at?: the character index at which to show the menu
  387. -- options.name?: The name to display in the info box
  388. -- options.type?: The type to display in the info box
  389. -- options.prefix?: The current type prefix (%Team)
  390. -- options.description?: The description for the currently active info box
  391. -- options.invalid?: If true, description is shown in red.
  392. -- options.isLast?: If true, auto complete won't keep going after this argument.
  393. function AutoComplete:Show (items, options)
  394. options = options or {}
  395.  
  396. -- Remove old options.
  397. for _, item in pairs(self.Items) do
  398. if item.gui then
  399. item.gui:Destroy()
  400. end
  401. end
  402.  
  403. -- Reset state
  404. self.SelectedItem = 1
  405. self.Items = items
  406. self.Prefix = options.prefix or ""
  407. self.LastItem = options.isLast or false
  408. self.Command = options.command
  409. self.Arg = options.arg
  410. self.NumArgs = options.numArgs
  411.  
  412. -- Generate the new option labels
  413. local autocompleteWidth = 200
  414.  
  415. for i, item in pairs(self.Items) do
  416. local leftText = item[1]
  417. local rightText = item[2]
  418.  
  419. if Shorthands[leftText] then
  420. leftText = rightText
  421. end
  422.  
  423. local btn = AutoItem:Clone()
  424. btn.Name = leftText .. rightText
  425. btn.BackgroundTransparency = i == self.SelectedItem and 0.5 or 1
  426. btn.Typed.Text = leftText
  427. btn.Suggest.Text = string.rep(" ", #leftText) .. rightText:sub(#leftText + 1)
  428. btn.Parent = Gui
  429. btn.LayoutOrder = i
  430.  
  431. local maxBounds = math.max(btn.Typed.TextBounds.X, btn.Suggest.TextBounds.X) + 20
  432. if maxBounds > autocompleteWidth then
  433. autocompleteWidth = maxBounds
  434. end
  435.  
  436. item.gui = btn
  437. end
  438.  
  439. Gui.UIListLayout:ApplyLayout()
  440.  
  441. -- Todo: Use TextService to find accurate position for auto complete box
  442. local text = Entry.TextBox.Text
  443. local words = Util.SplitString(text)
  444. if text:sub(#text, #text) == " " and not options.at then
  445. words[#words+1] = "e"
  446. end
  447. table.remove(words, #words)
  448. local extra = (options.at and options.at or (#table.concat(words, " ") + 1)) * 7
  449.  
  450. -- Update the auto complete container
  451. Gui.Position = UDim2.new(0, Entry.TextBox.AbsolutePosition.X - 10 + extra, 0, Entry.TextBox.AbsolutePosition.Y + 30)
  452. Gui.Size = UDim2.new(0, autocompleteWidth, 0, Gui.UIListLayout.AbsoluteContentSize.Y)
  453. Gui.Visible = true
  454.  
  455. -- Finally, update thge info display
  456. UpdateInfoDisplay(self.Items[1] and self.Items[1].options or options)
  457. end
  458.  
  459. --- Returns the selected item in the auto complete
  460. function AutoComplete:GetSelectedItem ()
  461. if Gui.Visible == false then
  462. return nil
  463. end
  464.  
  465. return AutoComplete.Items[AutoComplete.SelectedItem]
  466. end
  467.  
  468. --- Hides the auto complete
  469. function AutoComplete:Hide ()
  470. Gui.Visible = false
  471. end
  472.  
  473. --- Returns if the menu is visible
  474. function AutoComplete:IsVisible ()
  475. return Gui.Visible
  476. end
  477.  
  478. --- Changes the user's item selection by the given delta
  479. function AutoComplete:Select (delta)
  480. if not Gui.Visible then return end
  481.  
  482. self.SelectedItem = self.SelectedItem + delta
  483.  
  484. if self.SelectedItem > #self.Items then
  485. self.SelectedItem = 1
  486. elseif self.SelectedItem < 1 then
  487. self.SelectedItem = #self.Items
  488. end
  489.  
  490. for i, item in pairs(self.Items) do
  491. item.gui.BackgroundTransparency = i == self.SelectedItem and 0.5 or 1
  492. end
  493.  
  494. if self.Items[self.SelectedItem] and self.Items[self.SelectedItem].options then
  495. UpdateInfoDisplay(self.Items[self.SelectedItem].options or {})
  496. end
  497. end
  498.  
  499. return AutoComplete
  500. end
  501. ]]></ProtectedString>
  502. <BinaryString name="Tags"></BinaryString>
  503. </Properties>
  504. </Item>
  505. <Item class="ModuleScript" referent="RBX608CDE2293BD49E3B78C34371D6C8E65">
  506. <Properties>
  507. <Content name="LinkedSource"><null></null></Content>
  508. <string name="Name">Window</string>
  509. <string name="ScriptGuid">{6D536A57-C13E-4C1A-9E42-10CA9207B1CA}</string>
  510. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  511. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  512. -- @source https://github.com/evaera/Cmdr
  513. -- @rostrap Cmdr
  514. -- @author evaera
  515.  
  516. -- Here be dragons
  517. -- luacheck: ignore 212
  518. local GuiService = game:GetService("GuiService")
  519. local UserInputService = game:GetService("UserInputService")
  520. local TextService = game:GetService("TextService")
  521. local Players = game:GetService("Players")
  522. local Player = Players.LocalPlayer
  523.  
  524. local LINE_HEIGHT = 20
  525. local WINDOW_MAX_HEIGHT = 300
  526.  
  527. --- Window handles the command bar GUI
  528. local Window = {
  529. Valid = true,
  530. AutoComplete = nil,
  531. ProcessEntry = nil,
  532. OnTextChanged = nil,
  533. Cmdr = nil,
  534. HistoryState = nil,
  535. }
  536.  
  537. local Gui = Player:WaitForChild("PlayerGui"):WaitForChild("Cmdr"):WaitForChild("Frame")
  538. local Line = Gui:WaitForChild("Line")
  539. local Entry = Gui:WaitForChild("Entry")
  540.  
  541. Line.Parent = nil
  542.  
  543. --- Update the text entry label
  544. function Window:UpdateLabel()
  545. Entry.TextLabel.Text = Player.Name .. "@" .. self.Cmdr.PlaceName .. "$"
  546. Entry.TextLabel.Size = UDim2.new(0, Entry.TextLabel.TextBounds.X, 0, 20)
  547. Entry.TextBox.Position = UDim2.new(0, Entry.TextLabel.Size.X.Offset + 7, 0, 0)
  548. end
  549.  
  550. --- Get the text entry label
  551. function Window:GetLabel()
  552. return Entry.TextLabel.Text
  553. end
  554.  
  555. --- Recalculate the window height
  556. function Window:UpdateWindowHeight()
  557. local windowHeight = LINE_HEIGHT
  558.  
  559. for _, child in pairs(Gui:GetChildren()) do
  560. if child:IsA("GuiObject") then
  561. windowHeight = windowHeight + child.Size.Y.Offset
  562. end
  563. end
  564.  
  565. Gui.CanvasSize = UDim2.new(Gui.CanvasSize.X.Scale, Gui.CanvasSize.X.Offset, 0, windowHeight)
  566. Gui.Size =
  567. UDim2.new(
  568. Gui.Size.X.Scale,
  569. Gui.Size.X.Offset,
  570. 0,
  571. windowHeight > WINDOW_MAX_HEIGHT and WINDOW_MAX_HEIGHT or windowHeight
  572. )
  573.  
  574. Gui.CanvasPosition = Vector2.new(0, math.clamp(windowHeight - 300, 0, math.huge))
  575. end
  576.  
  577. --- Add a line to the command bar
  578. function Window:AddLine(text, color)
  579. if #text == 0 then
  580. Window:UpdateWindowHeight()
  581. return
  582. end
  583.  
  584. local str = self.Cmdr.Util.EmulateTabstops(text or "nil", 8)
  585. local line = Line:Clone()
  586. line.Size =
  587. UDim2.new(
  588. line.Size.X.Scale,
  589. line.Size.X.Offset,
  590. 0,
  591. TextService:GetTextSize(
  592. str,
  593. line.TextSize,
  594. line.Font,
  595. Vector2.new(Gui.UIListLayout.AbsoluteContentSize.X, math.huge)
  596. ).Y + (LINE_HEIGHT - line.TextSize)
  597. )
  598. line.Text = str
  599. line.TextColor3 = color or line.TextColor3
  600. line.Parent = Gui
  601. end
  602.  
  603. --- Returns if the command bar is visible
  604. function Window:IsVisible()
  605. return Gui.Visible
  606. end
  607.  
  608. --- Sets the command bar visible or not
  609. function Window:SetVisible(visible)
  610. Gui.Visible = visible
  611.  
  612. if visible then
  613. Entry.TextBox:CaptureFocus()
  614. self:SetEntryText("")
  615.  
  616. if self.Cmdr.ActivationUnlocksMouse then
  617. self.PreviousMouseBehavior = UserInputService.MouseBehavior
  618. UserInputService.MouseBehavior = Enum.MouseBehavior.Default
  619. end
  620. else
  621. Entry.TextBox:ReleaseFocus()
  622. self.AutoComplete:Hide()
  623.  
  624. if self.PreviousMouseBehavior then
  625. UserInputService.MouseBehavior = self.PreviousMouseBehavior
  626. self.PreviousMouseBehavior = nil
  627. end
  628. end
  629. end
  630.  
  631. --- Hides the command bar
  632. function Window:Hide()
  633. return self:SetVisible(false)
  634. end
  635.  
  636. --- Shows the command bar
  637. function Window:Show()
  638. return self:SetVisible(true)
  639. end
  640.  
  641. --- Sets the text in the command bar text box, and captures focus
  642. function Window:SetEntryText(text)
  643. Entry.TextBox.Text = text
  644.  
  645. if self:IsVisible() then
  646. Entry.TextBox:CaptureFocus()
  647. end
  648. end
  649.  
  650. --- Gets the text in the command bar text box
  651. function Window:GetEntryText()
  652. return Entry.TextBox.Text:gsub("\t", "")
  653. end
  654.  
  655. --- Sets whether the command is in a valid state or not.
  656. -- Cannot submit if in invalid state.
  657. function Window:SetIsValidInput(isValid, errorText)
  658. Entry.TextBox.TextColor3 = isValid and Color3.fromRGB(255, 255, 255) or Color3.fromRGB(255, 73, 73)
  659. self.Valid = isValid
  660. self._errorText = errorText
  661. end
  662.  
  663. --- Event handler for text box focus lost
  664. function Window:LoseFocus(submit)
  665. local text = Entry.TextBox.Text
  666.  
  667. self:ClearHistoryState()
  668.  
  669. if Gui.Visible and not GuiService.MenuIsOpen then
  670. -- self:SetEntryText("")
  671. Entry.TextBox:CaptureFocus()
  672. elseif GuiService.MenuIsOpen and Gui.Visible then
  673. self:Hide()
  674. end
  675.  
  676. if submit and self.Valid then
  677. wait()
  678. self:SetEntryText("")
  679. self.ProcessEntry(text)
  680. elseif submit then
  681. self:AddLine(self._errorText, Color3.fromRGB(255, 153, 153))
  682. end
  683. end
  684.  
  685. function Window:TraverseHistory(delta)
  686. local history = self.Cmdr.Dispatcher:GetHistory()
  687.  
  688. if self.HistoryState == nil then
  689. self.HistoryState = {
  690. Position = #history + 1;
  691. InitialText = self:GetEntryText();
  692. }
  693. end
  694.  
  695. self.HistoryState.Position = math.clamp(self.HistoryState.Position + delta, 1, #history + 1)
  696.  
  697. self:SetEntryText(
  698. self.HistoryState.Position == #history + 1
  699. and self.HistoryState.InitialText
  700. or history[self.HistoryState.Position]
  701. )
  702. end
  703.  
  704. function Window:ClearHistoryState()
  705. self.HistoryState = nil
  706. end
  707.  
  708. function Window:SelectVertical(delta)
  709. if self.AutoComplete:IsVisible() and not self.HistoryState then
  710. self.AutoComplete:Select(delta)
  711. else
  712. self:TraverseHistory(delta)
  713. end
  714. end
  715.  
  716. local lastPressTime = 0
  717. local pressCount = 0
  718. --- Handles user input when the box is focused
  719. function Window:BeginInput(input, gameProcessed)
  720. if GuiService.MenuIsOpen then
  721. self:Hide()
  722. end
  723.  
  724. if gameProcessed and self:IsVisible() == false then
  725. return
  726. end
  727.  
  728. if self.Cmdr.ActivationKeys[input.KeyCode] then -- Activate the command bar
  729. if self.Cmdr.MashToEnable and not self.Cmdr.Enabled then
  730. if tick() - lastPressTime < 1 then
  731. if pressCount >= 5 then
  732. return self.Cmdr:SetEnabled(true)
  733. else
  734. pressCount = pressCount + 1
  735. end
  736. else
  737. pressCount = 1
  738. end
  739. lastPressTime = tick()
  740. elseif self.Cmdr.Enabled then
  741. self:SetVisible(not self:IsVisible())
  742. wait()
  743. self:SetEntryText("")
  744.  
  745. if GuiService.MenuIsOpen then -- Special case for menu getting stuck open (roblox bug)
  746. self:Hide()
  747. end
  748. end
  749.  
  750. return
  751. end
  752.  
  753. if self.Cmdr.Enabled == false or not self:IsVisible() then
  754. if self:IsVisible() then
  755. self:Hide()
  756. end
  757.  
  758. return
  759. end
  760.  
  761. if input.KeyCode == Enum.KeyCode.Down then -- Auto Complete Down
  762. self:SelectVertical(1)
  763. elseif input.KeyCode == Enum.KeyCode.Up then -- Auto Complete Up
  764. self:SelectVertical(-1)
  765. elseif input.KeyCode == Enum.KeyCode.Return then -- Eat new lines
  766. wait()
  767. self:SetEntryText(self:GetEntryText():gsub("\n", ""):gsub("\r", ""))
  768. elseif input.KeyCode == Enum.KeyCode.Tab then -- Auto complete
  769. local item = self.AutoComplete:GetSelectedItem()
  770. local text = self:GetEntryText()
  771. if item and not (text:sub(#text, #text):match("%s") and self.AutoComplete.LastItem) then
  772. local replace = item[2]
  773. local newText
  774. local insertSpace = true
  775. local command = self.AutoComplete.Command
  776.  
  777. if command then
  778. local lastArg = self.AutoComplete.Arg
  779.  
  780. newText = command.Alias
  781. insertSpace = self.AutoComplete.NumArgs ~= #command.ArgumentDefinitions
  782.  
  783. local args = command.Arguments
  784. for i = 1, #args do
  785. local arg = args[i]
  786. local segments = arg.RawSegments
  787. if arg == lastArg then
  788. segments[#segments] = replace
  789. end
  790.  
  791. local argText = arg.Prefix .. table.concat(segments, ",")
  792.  
  793. -- Put auto completion options in quotation marks if they have a space
  794. if argText:find(" ") then
  795. argText = ("%q"):format(argText)
  796. end
  797.  
  798. newText = ("%s %s"):format(newText, argText)
  799.  
  800. if arg == lastArg then
  801. break
  802. end
  803. end
  804. else
  805. newText = replace
  806. end
  807. -- need to wait a frame so we can eat the \t
  808. wait()
  809. -- Update the text box
  810. self:SetEntryText(newText .. (insertSpace and " " or ""))
  811. else
  812. -- Still need to eat the \t even if there is no auto-complete to show
  813. wait()
  814. self:SetEntryText(self:GetEntryText())
  815. end
  816. else
  817. self:ClearHistoryState()
  818. end
  819. end
  820.  
  821. -- Hook events
  822. Entry.TextBox.FocusLost:Connect(
  823. function(submit)
  824. return Window:LoseFocus(submit)
  825. end
  826. )
  827.  
  828. UserInputService.InputBegan:Connect(
  829. function(input, gameProcessed)
  830. return Window:BeginInput(input, gameProcessed)
  831. end
  832. )
  833.  
  834. Entry.TextBox:GetPropertyChangedSignal("Text"):Connect(
  835. function()
  836. if Entry.TextBox.Text:match("\t") then -- Eat \t
  837. Entry.TextBox.Text = Entry.TextBox.Text:gsub("\t", "")
  838. return
  839. end
  840. if Window.OnTextChanged then
  841. return Window.OnTextChanged(Entry.TextBox.Text)
  842. end
  843. end
  844. )
  845.  
  846. Gui.ChildAdded:Connect(Window.UpdateWindowHeight)
  847.  
  848. return Window
  849. ]]></ProtectedString>
  850. <BinaryString name="Tags"></BinaryString>
  851. </Properties>
  852. </Item>
  853. </Item>
  854. <Item class="ModuleScript" referent="RBX3703B004929C4F1396DD20F7DAF0F8EF">
  855. <Properties>
  856. <Content name="LinkedSource"><null></null></Content>
  857. <string name="Name">CreateGui</string>
  858. <string name="ScriptGuid">{6AAC372A-F4F1-4F9E-B52F-81CAA1AC3127}</string>
  859. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  860. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  861. -- @source https://github.com/evaera/Cmdr
  862. -- @rostrap Cmdr
  863. -- @author evaera
  864.  
  865. --[[
  866. DO NOT MODIFY. This file is auto-generated.
  867. Plugin: https://www.roblox.com/library/2307140444/Object-to-Lua
  868. ]]
  869.  
  870. return function ()
  871. local Cmdr = Instance.new("ScreenGui")
  872. Cmdr.DisplayOrder = 1000
  873. Cmdr.Name = "Cmdr"
  874. Cmdr.ResetOnSpawn = false
  875.  
  876. local Frame = Instance.new("ScrollingFrame")
  877. Frame.BackgroundColor3 = Color3.fromRGB(17, 17, 17)
  878. Frame.BackgroundTransparency = 0.4
  879. Frame.BorderSizePixel = 0
  880. Frame.CanvasSize = UDim2.new(0, 0, 0, 100)
  881. Frame.Name = "Frame"
  882. Frame.Position = UDim2.new(0.025, 0, 0, 25)
  883. Frame.ScrollBarThickness = 6
  884. Frame.ScrollingDirection = Enum.ScrollingDirection.Y
  885. Frame.Selectable = false
  886. Frame.Size = UDim2.new(0.95, 0, 0, 50)
  887. Frame.Visible = false
  888. Frame.Parent = Cmdr
  889.  
  890. local Autocomplete = Instance.new("Frame")
  891. Autocomplete.BackgroundColor3 = Color3.fromRGB(59, 59, 59)
  892. Autocomplete.BackgroundTransparency = 0.5
  893. Autocomplete.BorderSizePixel = 0
  894. Autocomplete.Name = "Autocomplete"
  895. Autocomplete.Position = UDim2.new(0, 167, 0, 75)
  896. Autocomplete.Size = UDim2.new(0, 200, 0, 200)
  897. Autocomplete.Visible = false
  898. Autocomplete.Parent = Cmdr
  899.  
  900. local UIListLayout = Instance.new("UIListLayout")
  901. UIListLayout.SortOrder = Enum.SortOrder.LayoutOrder
  902. UIListLayout.Parent = Frame
  903.  
  904. local Line = Instance.new("TextLabel")
  905. Line.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
  906. Line.BackgroundTransparency = 1
  907. Line.Font = Enum.Font.Code
  908. Line.Name = "Line"
  909. Line.Size = UDim2.new(1, 0, 0, 20)
  910. Line.TextColor3 = Color3.fromRGB(255, 255, 255)
  911. Line.TextSize = 14
  912. Line.TextXAlignment = Enum.TextXAlignment.Left
  913. Line.Parent = Frame
  914.  
  915. local UIPadding = Instance.new("UIPadding")
  916. UIPadding.PaddingBottom = UDim.new(0, 10)
  917. UIPadding.PaddingLeft = UDim.new(0, 10)
  918. UIPadding.PaddingRight = UDim.new(0, 10)
  919. UIPadding.PaddingTop = UDim.new(0, 10)
  920. UIPadding.Parent = Frame
  921.  
  922. local Entry = Instance.new("Frame")
  923. Entry.BackgroundTransparency = 1
  924. Entry.LayoutOrder = 999999999
  925. Entry.Name = "Entry"
  926. Entry.Size = UDim2.new(1, 0, 0, 20)
  927. Entry.Parent = Frame
  928.  
  929. local UIListLayout2 = Instance.new("UIListLayout")
  930. UIListLayout2.SortOrder = Enum.SortOrder.LayoutOrder
  931. UIListLayout2.Parent = Autocomplete
  932.  
  933. local Title = Instance.new("Frame")
  934. Title.BackgroundColor3 = Color3.fromRGB(59, 59, 59)
  935. Title.BackgroundTransparency = 0.2
  936. Title.BorderSizePixel = 0
  937. Title.LayoutOrder = -2
  938. Title.Name = "Title"
  939. Title.Size = UDim2.new(1, 0, 0, 40)
  940. Title.Parent = Autocomplete
  941.  
  942. local Description = Instance.new("Frame")
  943. Description.BackgroundColor3 = Color3.fromRGB(59, 59, 59)
  944. Description.BackgroundTransparency = 0.2
  945. Description.BorderSizePixel = 0
  946. Description.LayoutOrder = -1
  947. Description.Name = "Description"
  948. Description.Size = UDim2.new(1, 0, 0, 20)
  949. Description.Parent = Autocomplete
  950.  
  951. local TextButton = Instance.new("TextButton")
  952. TextButton.BackgroundColor3 = Color3.fromRGB(59, 59, 59)
  953. TextButton.BackgroundTransparency = 0.5
  954. TextButton.BorderSizePixel = 0
  955. TextButton.Font = Enum.Font.Code
  956. TextButton.Size = UDim2.new(1, 0, 0, 30)
  957. TextButton.Text = ""
  958. TextButton.TextColor3 = Color3.fromRGB(255, 255, 255)
  959. TextButton.TextSize = 14
  960. TextButton.TextXAlignment = Enum.TextXAlignment.Left
  961. TextButton.Parent = Autocomplete
  962.  
  963. local TextBox = Instance.new("TextBox")
  964. TextBox.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
  965. TextBox.BackgroundTransparency = 1
  966. TextBox.ClearTextOnFocus = false
  967. TextBox.Font = Enum.Font.Code
  968. TextBox.LayoutOrder = 999999999
  969. TextBox.Position = UDim2.new(0, 140, 0, 0)
  970. TextBox.Size = UDim2.new(1, 0, 0, 20)
  971. TextBox.Text = "x"
  972. TextBox.TextColor3 = Color3.fromRGB(255, 255, 255)
  973. TextBox.TextSize = 14
  974. TextBox.TextXAlignment = Enum.TextXAlignment.Left
  975. TextBox.Parent = Entry
  976.  
  977. local TextLabel = Instance.new("TextLabel")
  978. TextLabel.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
  979. TextLabel.BackgroundTransparency = 1
  980. TextLabel.Font = Enum.Font.Code
  981. TextLabel.Size = UDim2.new(0, 133, 0, 20)
  982. TextLabel.Text = ""
  983. TextLabel.TextColor3 = Color3.fromRGB(255, 223, 93)
  984. TextLabel.TextSize = 14
  985. TextLabel.TextXAlignment = Enum.TextXAlignment.Left
  986. TextLabel.Parent = Entry
  987.  
  988. local Field = Instance.new("TextLabel")
  989. Field.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
  990. Field.BackgroundTransparency = 1
  991. Field.Font = Enum.Font.SourceSansBold
  992. Field.Name = "Field"
  993. Field.Size = UDim2.new(0, 37, 1, 0)
  994. Field.Text = "from"
  995. Field.TextColor3 = Color3.fromRGB(255, 255, 255)
  996. Field.TextSize = 20
  997. Field.TextXAlignment = Enum.TextXAlignment.Left
  998. Field.Parent = Title
  999.  
  1000. local UIPadding2 = Instance.new("UIPadding")
  1001. UIPadding2.PaddingLeft = UDim.new(0, 10)
  1002. UIPadding2.Parent = Title
  1003.  
  1004. local Label = Instance.new("TextLabel")
  1005. Label.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
  1006. Label.BackgroundTransparency = 1
  1007. Label.Font = Enum.Font.SourceSansLight
  1008. Label.Name = "Label"
  1009. Label.Size = UDim2.new(1, 0, 1, 0)
  1010. Label.Text = "The players to teleport. The players to teleport. The players to teleport. The players to teleport. "
  1011. Label.TextColor3 = Color3.fromRGB(255, 255, 255)
  1012. Label.TextSize = 16
  1013. Label.TextWrapped = true
  1014. Label.TextXAlignment = Enum.TextXAlignment.Left
  1015. Label.TextYAlignment = Enum.TextYAlignment.Top
  1016. Label.Parent = Description
  1017.  
  1018. local UIPadding3 = Instance.new("UIPadding")
  1019. UIPadding3.PaddingBottom = UDim.new(0, 10)
  1020. UIPadding3.PaddingLeft = UDim.new(0, 10)
  1021. UIPadding3.PaddingRight = UDim.new(0, 10)
  1022. UIPadding3.Parent = Description
  1023.  
  1024. local Typed = Instance.new("TextLabel")
  1025. Typed.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
  1026. Typed.BackgroundTransparency = 1
  1027. Typed.Font = Enum.Font.Code
  1028. Typed.Name = "Typed"
  1029. Typed.Size = UDim2.new(1, 0, 1, 0)
  1030. Typed.Text = "Lab"
  1031. Typed.TextColor3 = Color3.fromRGB(131, 222, 255)
  1032. Typed.TextSize = 14
  1033. Typed.TextXAlignment = Enum.TextXAlignment.Left
  1034. Typed.Parent = TextButton
  1035.  
  1036. local UIPadding4 = Instance.new("UIPadding")
  1037. UIPadding4.PaddingLeft = UDim.new(0, 10)
  1038. UIPadding4.Parent = TextButton
  1039.  
  1040. local Suggest = Instance.new("TextLabel")
  1041. Suggest.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
  1042. Suggest.BackgroundTransparency = 1
  1043. Suggest.Font = Enum.Font.Code
  1044. Suggest.Name = "Suggest"
  1045. Suggest.Size = UDim2.new(1, 0, 1, 0)
  1046. Suggest.Text = " el"
  1047. Suggest.TextColor3 = Color3.fromRGB(255, 255, 255)
  1048. Suggest.TextSize = 14
  1049. Suggest.TextXAlignment = Enum.TextXAlignment.Left
  1050. Suggest.Parent = TextButton
  1051.  
  1052. local Type = Instance.new("TextLabel")
  1053. Type.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
  1054. Type.BackgroundTransparency = 1
  1055. Type.BorderColor3 = Color3.fromRGB(255, 153, 153)
  1056. Type.Font = Enum.Font.SourceSans
  1057. Type.Name = "Type"
  1058. Type.Position = UDim2.new(1, 0, 0, 0)
  1059. Type.Size = UDim2.new(0, 0, 1, 0)
  1060. Type.Text = ": Players"
  1061. Type.TextColor3 = Color3.fromRGB(255, 255, 255)
  1062. Type.TextSize = 15
  1063. Type.TextXAlignment = Enum.TextXAlignment.Left
  1064. Type.Parent = Field
  1065.  
  1066. Cmdr.Parent = game:GetService('Players').LocalPlayer.PlayerGui
  1067. return Cmdr
  1068. end]]></ProtectedString>
  1069. <BinaryString name="Tags"></BinaryString>
  1070. </Properties>
  1071. </Item>
  1072. <Item class="Folder" referent="RBX47F98EC7EB6A4D6591877ED2C63BF730">
  1073. <Properties>
  1074. <string name="Name">Commands</string>
  1075. <BinaryString name="Tags"></BinaryString>
  1076. </Properties>
  1077. <Item class="Folder" referent="RBX4731997E92A644028AD089E27BBDAA2C">
  1078. <Properties>
  1079. <string name="Name">Def</string>
  1080. <BinaryString name="Tags"></BinaryString>
  1081. </Properties>
  1082. <Item class="ModuleScript" referent="RBXFD455615CEE34E55AB6C865CE2EA0E86">
  1083. <Properties>
  1084. <Content name="LinkedSource"><null></null></Content>
  1085. <string name="Name">alias</string>
  1086. <string name="ScriptGuid">{B21018D9-75E4-4E2E-847F-722175801FE8}</string>
  1087. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1088. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1089. -- @source https://github.com/evaera/Cmdr
  1090. -- @rostrap Cmdr
  1091. -- @author evaera
  1092.  
  1093. return {
  1094. Name = "alias";
  1095. Aliases = {};
  1096. Description = "Creates a new, single command out of a command and given arguments.";
  1097. Group = "DefaultUtil";
  1098. Args = {
  1099. {
  1100. Type = "string";
  1101. Name = "Alias name";
  1102. Description = "The key or input type you'd like to bind the command to."
  1103. },
  1104. {
  1105. Type = "string";
  1106. Name = "Command string";
  1107. Description = "The command text you want to run. Separate multiple commands with \"&&\". Accept arguments with $1, $2, $3, etc."
  1108. },
  1109. };
  1110.  
  1111. Run = function(context, name, commandString)
  1112. context.Cmdr.Registry:RegisterCommandObject(
  1113. context.Cmdr.Util.MakeAliasCommand(name, commandString)
  1114. )
  1115.  
  1116. return ("Created alias %q"):format(name)
  1117. end
  1118. }]]></ProtectedString>
  1119. <BinaryString name="Tags"></BinaryString>
  1120. </Properties>
  1121. </Item>
  1122. <Item class="ModuleScript" referent="RBXFD7DD76329D8401487311567F1117501">
  1123. <Properties>
  1124. <Content name="LinkedSource"><null></null></Content>
  1125. <string name="Name">bind</string>
  1126. <string name="ScriptGuid">{ACEB33F1-B5FC-44FE-A1BD-767A8A49B89E}</string>
  1127. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1128. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1129. -- @source https://github.com/evaera/Cmdr
  1130. -- @rostrap Cmdr
  1131. -- @author evaera
  1132.  
  1133. local UserInputService = game:GetService("UserInputService")
  1134.  
  1135. return {
  1136. Name = "bind";
  1137. Aliases = {};
  1138. Description = "Binds a command string to a key or mouse input.";
  1139. Group = "DefaultUtil";
  1140. Args = {
  1141. {
  1142. Type = "userInput ! bindableResource @ player";
  1143. Name = "Input";
  1144. Description = "The key or input type you'd like to bind the command to."
  1145. },
  1146. {
  1147. Type = "command";
  1148. Name = "Command";
  1149. Description = "The command you want to run on this input"
  1150. },
  1151. {
  1152. Type = "string";
  1153. Name = "Arguments";
  1154. Description = "The arguments for the command";
  1155. Default = "";
  1156. }
  1157. };
  1158.  
  1159. Run = function(context, bind, command, arguments)
  1160. local binds = context:GetStore("CMDR_Binds")
  1161.  
  1162. command = command .. " " .. arguments
  1163.  
  1164. if binds[bind] then
  1165. binds[bind]:Disconnect()
  1166. end
  1167.  
  1168. local bindType = context:GetArgument(1).Type.Name
  1169.  
  1170. if bindType == "userInput" then
  1171. binds[bind] = UserInputService.InputBegan:Connect(function(input, gameProcessed)
  1172. if gameProcessed then
  1173. return
  1174. end
  1175.  
  1176. if input.UserInputType == bind or input.KeyCode == bind then
  1177. context:Reply(context.Dispatcher:EvaluateAndRun(context.Cmdr.Util.RunEmbeddedCommands(context.Dispatcher, command)))
  1178. end
  1179. end)
  1180. elseif bindType == "bindableResource" then
  1181. return "Unimplemented..."
  1182. elseif bindType == "player" then
  1183. binds[bind] = bind.Chatted:Connect(function(message)
  1184. local args = { message }
  1185. local chatCommand = context.Cmdr.Util.RunEmbeddedCommands(context.Dispatcher, context.Cmdr.Util.SubstituteArgs(command, args))
  1186. context:Reply(("%s $ %s : %s"):format(
  1187. bind.Name,
  1188. chatCommand,
  1189. context.Dispatcher:EvaluateAndRun(chatCommand)
  1190. ), Color3.fromRGB(244, 92, 66))
  1191. end)
  1192. end
  1193.  
  1194.  
  1195. return "Bound command to input."
  1196. end
  1197. }]]></ProtectedString>
  1198. <BinaryString name="Tags"></BinaryString>
  1199. </Properties>
  1200. </Item>
  1201. <Item class="ModuleScript" referent="RBX7A73A217C3A240B28E24B4DC2606B120">
  1202. <Properties>
  1203. <Content name="LinkedSource"><null></null></Content>
  1204. <string name="Name">clear</string>
  1205. <string name="ScriptGuid">{B5F9EAF9-D44F-492D-9B6C-AAA30D096857}</string>
  1206. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1207. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1208. -- @source https://github.com/evaera/Cmdr
  1209. -- @rostrap Cmdr
  1210. -- @author evaera
  1211.  
  1212. local Players = game:GetService("Players")
  1213.  
  1214. return {
  1215. Name = "clear",
  1216. Aliases = {},
  1217. Description = "Clear all lines above the entry line of the Cmdr window.",
  1218. Group = "DefaultUtil",
  1219. Args = {},
  1220. Run = function()
  1221. local player = Players.LocalPlayer
  1222. local gui = player:WaitForChild("PlayerGui"):WaitForChild("Cmdr")
  1223. local frame = gui:WaitForChild("Frame")
  1224.  
  1225. if gui and frame then
  1226. for _, child in pairs(frame:GetChildren()) do
  1227. if child.Name == "Line" and child:IsA("TextLabel") then
  1228. child:Destroy()
  1229. end
  1230. end
  1231. end
  1232. return ""
  1233. end
  1234. }
  1235. ]]></ProtectedString>
  1236. <BinaryString name="Tags"></BinaryString>
  1237. </Properties>
  1238. </Item>
  1239. <Item class="ModuleScript" referent="RBX34CA904CCCA54EFE8BE1C154B1A37233">
  1240. <Properties>
  1241. <Content name="LinkedSource"><null></null></Content>
  1242. <string name="Name">echo</string>
  1243. <string name="ScriptGuid">{206CE708-94B9-4EF9-99C1-ED0CB0B86997}</string>
  1244. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1245. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1246. -- @source https://github.com/evaera/Cmdr
  1247. -- @rostrap Cmdr
  1248. -- @author evaera
  1249.  
  1250. return {
  1251. Name = "echo";
  1252. Aliases = {};
  1253. Description = "Echoes your text back to you.";
  1254. Group = "DefaultUtil";
  1255. Args = {
  1256. {
  1257. Type = "string";
  1258. Name = "Text";
  1259. Description = "The text."
  1260. },
  1261. };
  1262.  
  1263. Run = function(_, text)
  1264. return text
  1265. end
  1266. }]]></ProtectedString>
  1267. <BinaryString name="Tags"></BinaryString>
  1268. </Properties>
  1269. </Item>
  1270. <Item class="ModuleScript" referent="RBXB3DDC350AF6A40458400D914350D912D">
  1271. <Properties>
  1272. <Content name="LinkedSource"><null></null></Content>
  1273. <string name="Name">history</string>
  1274. <string name="ScriptGuid">{F1CDCC16-9A1F-48DD-8A9D-8B8DC961C0BC}</string>
  1275. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1276. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1277. -- @source https://github.com/evaera/Cmdr
  1278. -- @rostrap Cmdr
  1279. -- @author evaera
  1280.  
  1281. return {
  1282. Name = "history";
  1283. Aliases = {};
  1284. AutoExec = {
  1285. "alias ! run ${history $1}";
  1286. "alias ^ run ${run replace ${history -1} $1 $2}";
  1287. "alias !! ! -1";
  1288. };
  1289. Description = "Displays previous commands from history.";
  1290. Group = "DefaultUtil";
  1291. Args = {
  1292. {
  1293. Type = "integer";
  1294. Name = "Line Number";
  1295. Description = "Command line number (can be negative to go from end)"
  1296. },
  1297. };
  1298.  
  1299. Run = function(context, line)
  1300. local history = context.Dispatcher:GetHistory()
  1301.  
  1302. if line <= 0 then
  1303. line = #history + line
  1304. end
  1305.  
  1306. return history[line] or ""
  1307. end
  1308. }]]></ProtectedString>
  1309. <BinaryString name="Tags"></BinaryString>
  1310. </Properties>
  1311. </Item>
  1312. <Item class="ModuleScript" referent="RBX676C36DC4E034FC9BF0B5483872436C9">
  1313. <Properties>
  1314. <Content name="LinkedSource"><null></null></Content>
  1315. <string name="Name">replace</string>
  1316. <string name="ScriptGuid">{7DC0CEEF-77FC-4E75-80C3-DF429AF7FE3D}</string>
  1317. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1318. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1319. -- @source https://github.com/evaera/Cmdr
  1320. -- @rostrap Cmdr
  1321. -- @author evaera
  1322.  
  1323. return {
  1324. Name = "replace";
  1325. Aliases = {};
  1326. Description = "Replaces text A with text B";
  1327. Group = "DefaultUtil";
  1328. Args = {
  1329. {
  1330. Type = "string";
  1331. Name = "Haystack";
  1332. Description = "The source string upon which to perform replacement."
  1333. },
  1334. {
  1335. Type = "string";
  1336. Name = "Needle";
  1337. Description = "The string pattern search for."
  1338. },
  1339. {
  1340. Type = "string";
  1341. Name = "Replacement";
  1342. Description = "The string to replace matches (%1 to insert matches)."
  1343. },
  1344. };
  1345.  
  1346. Run = function(_, haystack, needle, replacement)
  1347. return haystack:gsub(needle, replacement)
  1348. end
  1349. }]]></ProtectedString>
  1350. <BinaryString name="Tags"></BinaryString>
  1351. </Properties>
  1352. </Item>
  1353. <Item class="ModuleScript" referent="RBXBE09863FAB334CFA9929D6C87FFA2A1C">
  1354. <Properties>
  1355. <Content name="LinkedSource"><null></null></Content>
  1356. <string name="Name">run</string>
  1357. <string name="ScriptGuid">{E604A54B-4745-4AF6-A742-9F37223C0E6D}</string>
  1358. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1359. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1360. -- @source https://github.com/evaera/Cmdr
  1361. -- @rostrap Cmdr
  1362. -- @author evaera
  1363.  
  1364. return {
  1365. Name = "run";
  1366. Aliases = {};
  1367. AutoExec = {
  1368. "alias discard replace ${run $1} .* \\\"\\\""
  1369. };
  1370. Description = "Runs a given command string (replacing embedded commands).";
  1371. Group = "DefaultUtil";
  1372. Args = {
  1373. {
  1374. Type = "string";
  1375. Name = "Command";
  1376. Description = "The command string to run"
  1377. },
  1378. };
  1379.  
  1380. Run = function(context, command)
  1381. return context.Dispatcher:EvaluateAndRun(context.Cmdr.Util.RunEmbeddedCommands(context.Dispatcher, command))
  1382. end
  1383. }]]></ProtectedString>
  1384. <BinaryString name="Tags"></BinaryString>
  1385. </Properties>
  1386. </Item>
  1387. <Item class="ModuleScript" referent="RBX692EA8693EDA40CDAE85A5547E3FE20F">
  1388. <Properties>
  1389. <Content name="LinkedSource"><null></null></Content>
  1390. <string name="Name">runif</string>
  1391. <string name="ScriptGuid">{C83830D5-BB89-4EC5-8FD7-252E1E0905A6}</string>
  1392. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1393. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1394. -- @source https://github.com/evaera/Cmdr
  1395. -- @rostrap Cmdr
  1396. -- @author evaera
  1397.  
  1398. local conditions = {
  1399. startsWith = function (text, arg)
  1400. if text:sub(1, #arg) == arg then
  1401. return text:sub(#arg + 1)
  1402. end
  1403. end
  1404. }
  1405.  
  1406. return {
  1407. Name = "runif";
  1408. Aliases = {};
  1409. Description = "Runs a given command string if a certain condition is met.";
  1410. Group = "DefaultUtil";
  1411. Args = {
  1412. {
  1413. Type = "conditionFunction";
  1414. Name = "Condition";
  1415. Description = "The condition function"
  1416. },
  1417. {
  1418. Type = "string";
  1419. Name = "Argument";
  1420. Description = "The argument to the condition function"
  1421. },
  1422. {
  1423. Type = "string";
  1424. Name = "Test against";
  1425. Description = "The text to test against."
  1426. },
  1427. {
  1428. Type = "string";
  1429. Name = "Command";
  1430. Description = "The command string to run if requirements are met. If omitted, return value from condition function is used.";
  1431. Optional = true;
  1432. },
  1433. };
  1434.  
  1435. Run = function(context, condition, arg, testAgainst, command)
  1436. local conditionFunc = conditions[condition]
  1437.  
  1438. if not conditionFunc then
  1439. return ("Condition %q is not valid."):format(condition)
  1440. end
  1441.  
  1442. local text = conditionFunc(testAgainst, arg)
  1443.  
  1444. if text then
  1445. return context.Dispatcher:EvaluateAndRun(context.Cmdr.Util.RunEmbeddedCommands(context.Dispatcher, command or text))
  1446. end
  1447.  
  1448. return ""
  1449. end
  1450. }]]></ProtectedString>
  1451. <BinaryString name="Tags"></BinaryString>
  1452. </Properties>
  1453. </Item>
  1454. <Item class="ModuleScript" referent="RBX301C5052F0B7472097D6286887CACD42">
  1455. <Properties>
  1456. <Content name="LinkedSource"><null></null></Content>
  1457. <string name="Name">unbind</string>
  1458. <string name="ScriptGuid">{ABEB5DC5-66D5-4685-A15C-AA011202392A}</string>
  1459. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1460. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1461. -- @source https://github.com/evaera/Cmdr
  1462. -- @rostrap Cmdr
  1463. -- @author evaera
  1464.  
  1465. return {
  1466. Name = "unbind";
  1467. Aliases = {};
  1468. Description = "Unbinds an input previously bound with Bind";
  1469. Group = "DefaultUtil";
  1470. Args = {
  1471. {
  1472. Type = "userInput ! bindableResource @ player";
  1473. Name = "Input/Key";
  1474. Description = "The key or input type you'd like to unbind."
  1475. }
  1476. };
  1477.  
  1478. Run = function(context, inputEnum)
  1479. local binds = context:GetStore("CMDR_Binds")
  1480.  
  1481. if binds[inputEnum] then
  1482. binds[inputEnum]:Disconnect()
  1483. binds[inputEnum] = nil
  1484. return "Unbound command from input."
  1485. else
  1486. return "That input wasn't bound."
  1487. end
  1488. end
  1489. }]]></ProtectedString>
  1490. <BinaryString name="Tags"></BinaryString>
  1491. </Properties>
  1492. </Item>
  1493. <Item class="ModuleScript" referent="RBX9601429EDA45475CA90D07B97A5CC78B">
  1494. <Properties>
  1495. <Content name="LinkedSource"><null></null></Content>
  1496. <string name="Name">eval</string>
  1497. <string name="ScriptGuid">{9AC42E12-BCE6-4328-AB30-043D1EEFDAB9}</string>
  1498. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1499. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1500. -- @source https://github.com/evaera/Cmdr
  1501. -- @rostrap Cmdr
  1502. -- @author evaera
  1503.  
  1504. return {
  1505. Name = "eval";
  1506. Aliases = {"exec"};
  1507. Description = "Executes code";
  1508. Group = "DefaultUtil";
  1509. Args = {
  1510. {
  1511. Type = "string";
  1512. Name = "Source";
  1513. Description = "Code you wish to run"
  1514. }
  1515. };
  1516.  
  1517. Run = function(context, src)
  1518. local f = context.Cmdr.Loadstring(src)
  1519. if f then
  1520. local e = getfenv(f)
  1521. e.Cmdr = context.Cmdr
  1522. e.Context = context
  1523.  
  1524. return f()
  1525. end
  1526.  
  1527. return "Failed to run"
  1528. end
  1529. }]]></ProtectedString>
  1530. <BinaryString name="Tags"></BinaryString>
  1531. </Properties>
  1532. </Item>
  1533. <Item class="ModuleScript" referent="RBX825A72F9D24341DA8AF01E1B9F021D27">
  1534. <Properties>
  1535. <Content name="LinkedSource"><null></null></Content>
  1536. <string name="Name">help</string>
  1537. <string name="ScriptGuid">{D0768F0F-B8EC-4F54-8FAF-BDAD2E095F8A}</string>
  1538. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1539. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1540. -- @source https://github.com/evaera/Cmdr
  1541. -- @rostrap Cmdr
  1542. -- @author evaera
  1543.  
  1544. return {
  1545. Name = "help";
  1546. Description = "Displays a list of all commands, or inspects one command.";
  1547. Group = "Help";
  1548. Args = {
  1549. {
  1550. Type = "command";
  1551. Name = "Command";
  1552. Description = "The command to view information on";
  1553. Optional = true;
  1554. },
  1555. };
  1556.  
  1557. Run = function (context, commandName)
  1558. if commandName then
  1559. local command = context.Cmdr.Registry:GetCommand(commandName)
  1560. context:Reply(("Command: %s"):format(command.Name), Color3.fromRGB(230, 126, 34))
  1561. if command.Aliases and #command.Aliases > 0 then
  1562. context:Reply(("Aliases: %s"):format(table.concat(command.Aliases, ", ")), Color3.fromRGB(230, 230, 230))
  1563. end
  1564. context:Reply(command.Description, Color3.fromRGB(230, 230, 230))
  1565. for i, arg in ipairs(command.Args) do
  1566. context:Reply(("#%d %s%s: %s - %s"):format(
  1567. i,
  1568. arg.Name,
  1569. arg.Optional == true and "?" or "",
  1570. arg.Type, arg.Description
  1571. ))
  1572. end
  1573. else
  1574. local commands = context.Cmdr.Registry:GetCommands()
  1575.  
  1576. for _, cmd in pairs(commands) do
  1577. context:Reply(("%s - %s"):format(cmd.Name, cmd.Description))
  1578. end
  1579. end
  1580. return ""
  1581. end;
  1582. }]]></ProtectedString>
  1583. <BinaryString name="Tags"></BinaryString>
  1584. </Properties>
  1585. </Item>
  1586. </Item>
  1587. <Item class="ModuleScript" referent="RBX1E0E6A007EB24761B56F8943089A7AAE">
  1588. <Properties>
  1589. <Content name="LinkedSource"><null></null></Content>
  1590. <string name="Name">LightsaberBattlegrounds</string>
  1591. <string name="ScriptGuid">{792920A8-AE46-412D-8D0B-B4B1581A6BDF}</string>
  1592. <ProtectedString name="Source"><![CDATA[return function()
  1593. return game.GameId == 1351881085
  1594. end]]></ProtectedString>
  1595. <BinaryString name="Tags"></BinaryString>
  1596. </Properties>
  1597. <Item class="ModuleScript" referent="RBX99AD8FE961E145D48066AF9CE6A9CDF6">
  1598. <Properties>
  1599. <Content name="LinkedSource"><null></null></Content>
  1600. <string name="Name">Platform</string>
  1601. <string name="ScriptGuid">{B2DF7DF4-1B01-4F1E-9CEF-5C9D8D78F6AE}</string>
  1602. <ProtectedString name="Source"><![CDATA[return {
  1603. Name = "platform";
  1604. Aliases = {};
  1605. Description = "Controls platform";
  1606. Group = "DefaultUtil";
  1607. Args = {
  1608. {
  1609. Type = "string";
  1610. Name = "Action";
  1611. Description = "Action you wish to execute with the platform"
  1612. },
  1613. };
  1614.  
  1615. Run = function(_, text)
  1616.  
  1617. local console = workspace:FindFirstChild('Console', true)
  1618.  
  1619. text = text:lower()
  1620. if text == 'up' then
  1621. click_detector(console.Panel.Up.ClickDetector, 1)
  1622. elseif text == 'down' then
  1623. click_detector(console.Panel.Down.ClickDetector, 1)
  1624. elseif text == 'toggle' then
  1625. click_detector(console.Panel.Close.ClickDetector, 1)
  1626. end
  1627.  
  1628. return "Success"
  1629. end
  1630. }]]></ProtectedString>
  1631. <BinaryString name="Tags"></BinaryString>
  1632. </Properties>
  1633. </Item>
  1634. <Item class="ModuleScript" referent="RBX5CAFD43B6C4E442594425E2D9A02C968">
  1635. <Properties>
  1636. <Content name="LinkedSource"><null></null></Content>
  1637. <string name="Name">SetWeaponSpeed</string>
  1638. <string name="ScriptGuid">{DFAEA287-2663-4BBE-986D-DEA8E021FAA7}</string>
  1639. <ProtectedString name="Source"><![CDATA[return {
  1640. Name = "setweaponspeed";
  1641. Aliases = {};
  1642. Description = "Sets weapon speed";
  1643. Group = "DefaultUtil";
  1644. Args = {
  1645. {
  1646. Type = "number";
  1647. Name = "Speed";
  1648. Description = "New weapon speed"
  1649. },
  1650. };
  1651.  
  1652. Run = function(_, number)
  1653. local weapon = game:GetService('Players').LocalPlayer.Character:FindFirstChildWhichIsA('Tool')
  1654. if weapon then
  1655. weapon.Settings.Speed.Value = number
  1656. end
  1657. end
  1658. }]]></ProtectedString>
  1659. <BinaryString name="Tags"></BinaryString>
  1660. </Properties>
  1661. </Item>
  1662. </Item>
  1663. </Item>
  1664. <Item class="Folder" referent="RBX931A1E5FD65F4602B4D075C659ED04A5">
  1665. <Properties>
  1666. <string name="Name">Types</string>
  1667. <BinaryString name="Tags"></BinaryString>
  1668. </Properties>
  1669. <Item class="ModuleScript" referent="RBXCEE88289152742518A219084636CF9E1">
  1670. <Properties>
  1671. <Content name="LinkedSource"><null></null></Content>
  1672. <string name="Name">BindableResource</string>
  1673. <string name="ScriptGuid">{003CDED7-3D2B-4AE8-8FFE-E754EE143765}</string>
  1674. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1675. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1676. -- @source https://github.com/evaera/Cmdr
  1677. -- @rostrap Cmdr
  1678. -- @author evaera
  1679.  
  1680. return function (registry)
  1681. registry:RegisterType("bindableResource", registry.Cmdr.Util.MakeEnumType("BindableResource", {"Chat"}))
  1682. end
  1683. ]]></ProtectedString>
  1684. <BinaryString name="Tags"></BinaryString>
  1685. </Properties>
  1686. </Item>
  1687. <Item class="ModuleScript" referent="RBX638C439C98D54A30B32D74C6A8956490">
  1688. <Properties>
  1689. <Content name="LinkedSource"><null></null></Content>
  1690. <string name="Name">BrickColor</string>
  1691. <string name="ScriptGuid">{3C24E196-5B6C-4F7F-8015-C41B2B9B37C5}</string>
  1692. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1693. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1694. -- @source https://github.com/evaera/Cmdr
  1695. -- @rostrap Cmdr
  1696. -- @author evaera
  1697.  
  1698. local Util = require(script.Parent.Parent.Shared.Util)
  1699.  
  1700. local brickColorNames = {
  1701. "White", "Grey", "Light yellow", "Brick yellow", "Light green (Mint)", "Light reddish violet", "Pastel Blue",
  1702. "Light orange brown", "Nougat", "Bright red", "Med. reddish violet", "Bright blue", "Bright yellow", "Earth orange",
  1703. "Black", "Dark grey", "Dark green", "Medium green", "Lig. Yellowich orange", "Bright green", "Dark orange",
  1704. "Light bluish violet", "Transparent", "Tr. Red", "Tr. Lg blue", "Tr. Blue", "Tr. Yellow", "Light blue",
  1705. "Tr. Flu. Reddish orange", "Tr. Green", "Tr. Flu. Green", "Phosph. White", "Light red", "Medium red", "Medium blue",
  1706. "Light grey", "Bright violet", "Br. yellowish orange", "Bright orange", "Bright bluish green", "Earth yellow",
  1707. "Bright bluish violet", "Tr. Brown", "Medium bluish violet", "Tr. Medi. reddish violet", "Med. yellowish green",
  1708. "Med. bluish green", "Light bluish green", "Br. yellowish green", "Lig. yellowish green", "Med. yellowish orange",
  1709. "Br. reddish orange", "Bright reddish violet", "Light orange", "Tr. Bright bluish violet", "Gold", "Dark nougat",
  1710. "Silver", "Neon orange", "Neon green", "Sand blue", "Sand violet", "Medium orange", "Sand yellow", "Earth blue",
  1711. "Earth green", "Tr. Flu. Blue", "Sand blue metallic", "Sand violet metallic", "Sand yellow metallic",
  1712. "Dark grey metallic", "Black metallic", "Light grey metallic", "Sand green", "Sand red", "Dark red",
  1713. "Tr. Flu. Yellow", "Tr. Flu. Red", "Gun metallic", "Red flip/flop", "Yellow flip/flop", "Silver flip/flop", "Curry",
  1714. "Fire Yellow", "Flame yellowish orange", "Reddish brown", "Flame reddish orange", "Medium stone grey", "Royal blue",
  1715. "Dark Royal blue", "Bright reddish lilac", "Dark stone grey", "Lemon metalic", "Light stone grey", "Dark Curry",
  1716. "Faded green", "Turquoise", "Light Royal blue", "Medium Royal blue", "Rust", "Brown", "Reddish lilac", "Lilac",
  1717. "Light lilac", "Bright purple", "Light purple", "Light pink", "Light brick yellow", "Warm yellowish orange",
  1718. "Cool yellow", "Dove blue", "Medium lilac", "Slime green", "Smoky grey", "Dark blue", "Parsley green", "Steel blue",
  1719. "Storm blue", "Lapis", "Dark indigo", "Sea green", "Shamrock", "Fossil", "Mulberry", "Forest green", "Cadet blue",
  1720. "Electric blue", "Eggplant", "Moss", "Artichoke", "Sage green", "Ghost grey", "Lilac", "Plum", "Olivine",
  1721. "Laurel green", "Quill grey", "Crimson", "Mint", "Baby blue", "Carnation pink", "Persimmon", "Maroon", "Gold",
  1722. "Daisy orange", "Pearl", "Fog", "Salmon", "Terra Cotta", "Cocoa", "Wheat", "Buttermilk", "Mauve", "Sunrise",
  1723. "Tawny", "Rust", "Cashmere", "Khaki", "Lily white", "Seashell", "Burgundy", "Cork", "Burlap", "Beige", "Oyster",
  1724. "Pine Cone", "Fawn brown", "Hurricane grey", "Cloudy grey", "Linen", "Copper", "Dirt brown", "Bronze", "Flint",
  1725. "Dark taupe", "Burnt Sienna", "Institutional white", "Mid gray", "Really black", "Really red", "Deep orange",
  1726. "Alder", "Dusty Rose", "Olive", "New Yeller", "Really blue", "Navy blue", "Deep blue", "Cyan", "CGA brown",
  1727. "Magenta", "Pink", "Deep orange", "Teal", "Toothpaste", "Lime green", "Camo", "Grime", "Lavender",
  1728. "Pastel light blue", "Pastel orange", "Pastel violet", "Pastel blue-green", "Pastel green", "Pastel yellow",
  1729. "Pastel brown", "Royal purple", "Hot pink"
  1730. }
  1731.  
  1732. local brickColorFinder = Util.MakeFuzzyFinder(brickColorNames)
  1733.  
  1734. local brickColorType = {
  1735. Transform = function(text)
  1736. local brickColors = {}
  1737. for i, name in pairs(brickColorFinder(text)) do
  1738. brickColors[i] = BrickColor.new(name)
  1739. end
  1740. return brickColors
  1741. end;
  1742.  
  1743. Validate = function(brickColors)
  1744. return #brickColors > 0, "No valid brick colors with that name could be found."
  1745. end;
  1746.  
  1747. Autocomplete = function(brickColors)
  1748. return Util.GetNames(brickColors)
  1749. end;
  1750.  
  1751. Parse = function(brickColors)
  1752. return brickColors[1]
  1753. end;
  1754. }
  1755.  
  1756. local brickColor3Type = {
  1757. Transform = brickColorType.Transform;
  1758. Validate = brickColorType.Validate;
  1759. Autocomplete = brickColorType.Autocomplete;
  1760.  
  1761. Parse = function(brickColors)
  1762. return brickColors[1].Color
  1763. end;
  1764. }
  1765.  
  1766. return function(registry)
  1767. registry:RegisterType("brickColor", brickColorType)
  1768. registry:RegisterType("brickColors", Util.MakeListableType(brickColorType))
  1769.  
  1770. registry:RegisterType("brickColor3", brickColor3Type)
  1771. registry:RegisterType("brickColor3s", Util.MakeListableType(brickColor3Type))
  1772. end]]></ProtectedString>
  1773. <BinaryString name="Tags"></BinaryString>
  1774. </Properties>
  1775. </Item>
  1776. <Item class="ModuleScript" referent="RBXEC1ED03605AE47CD8EE8B48015D5FA3D">
  1777. <Properties>
  1778. <Content name="LinkedSource"><null></null></Content>
  1779. <string name="Name">Color3</string>
  1780. <string name="ScriptGuid">{B560A0F5-2B93-4FD6-8EF7-3FE8336874EB}</string>
  1781. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1782. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1783. -- @source https://github.com/evaera/Cmdr
  1784. -- @rostrap Cmdr
  1785. -- @author evaera
  1786.  
  1787. local Util = require(script.Parent.Parent.Shared.Util)
  1788.  
  1789. local color3Type = Util.MakeSequenceType({
  1790. ValidateEach = function(value, i)
  1791. if value == nil then
  1792. return false, ("Invalid or missing number at position %d in Color3 type."):format(i)
  1793. elseif value < 0 or value > 255 then
  1794. return false, ("Number out of acceptable range 0-255 at position %d in Color3 type."):format(i)
  1795. elseif value % 1 ~= 0 then
  1796. return false, ("Number is not an integer at position %d in Color3 type."):format(i)
  1797. end
  1798.  
  1799. return true
  1800. end;
  1801. TransformEach = tonumber;
  1802. Constructor = Color3.fromRGB;
  1803. Length = 3;
  1804. })
  1805.  
  1806. local function parseHexDigit(x)
  1807. if #x == 1 then
  1808. x = x .. x
  1809. end
  1810.  
  1811. return tonumber(x, 16)
  1812. end
  1813.  
  1814. local hexColor3Type = {
  1815. Transform = function(text)
  1816. local r, g, b = text:match("^#?(%x%x?)(%x%x?)(%x%x?)$")
  1817. return Util.Each(parseHexDigit, r, g, b)
  1818. end;
  1819.  
  1820. Validate = function(r, g, b)
  1821. return r ~= nil and g ~= nil and b ~= nil, "Invalid hex color"
  1822. end;
  1823.  
  1824. Parse = function(...)
  1825. return Color3.fromRGB(...)
  1826. end;
  1827. }
  1828.  
  1829. return function (cmdr)
  1830. cmdr:RegisterType("color3", color3Type)
  1831. cmdr:RegisterType("color3s", Util.MakeListableType(color3Type))
  1832.  
  1833. cmdr:RegisterType("hexColor3", hexColor3Type)
  1834. cmdr:RegisterType("hexColor3s", Util.MakeListableType(hexColor3Type))
  1835. end]]></ProtectedString>
  1836. <BinaryString name="Tags"></BinaryString>
  1837. </Properties>
  1838. </Item>
  1839. <Item class="ModuleScript" referent="RBXED5B094136AB418088F79E4D37ADAF02">
  1840. <Properties>
  1841. <Content name="LinkedSource"><null></null></Content>
  1842. <string name="Name">Command</string>
  1843. <string name="ScriptGuid">{A38076EA-89FD-4B05-A661-384DC2CD4618}</string>
  1844. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1845. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1846. -- @source https://github.com/evaera/Cmdr
  1847. -- @rostrap Cmdr
  1848. -- @author evaera
  1849.  
  1850. local Util = require(script.Parent.Parent.Shared.Util)
  1851.  
  1852. return function (cmdr)
  1853. local commandType = {
  1854. Transform = function (text)
  1855. local findCommand = Util.MakeFuzzyFinder(cmdr:GetCommandsAsStrings())
  1856.  
  1857. return findCommand(text)
  1858. end;
  1859.  
  1860. Validate = function (commands)
  1861. return #commands > 0, "No command with that name could be found."
  1862. end;
  1863.  
  1864. Autocomplete = function (commands)
  1865. return commands
  1866. end;
  1867.  
  1868. Parse = function (commands)
  1869. return commands[1]
  1870. end;
  1871. }
  1872.  
  1873. cmdr:RegisterType("command", commandType)
  1874. cmdr:RegisterType("commands", Util.MakeListableType(commandType))
  1875. end]]></ProtectedString>
  1876. <BinaryString name="Tags"></BinaryString>
  1877. </Properties>
  1878. </Item>
  1879. <Item class="ModuleScript" referent="RBXD77FD4D79FE34C98B3486A695AD6880E">
  1880. <Properties>
  1881. <Content name="LinkedSource"><null></null></Content>
  1882. <string name="Name">ConditionFunction</string>
  1883. <string name="ScriptGuid">{CBE4A528-0A6A-4006-B652-3A2CBD6CA7FE}</string>
  1884. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1885. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1886. -- @source https://github.com/evaera/Cmdr
  1887. -- @rostrap Cmdr
  1888. -- @author evaera
  1889.  
  1890. return function (registry)
  1891. registry:RegisterType("conditionFunction", registry.Cmdr.Util.MakeEnumType("ConditionFunction", {"startsWith"}))
  1892. end
  1893. ]]></ProtectedString>
  1894. <BinaryString name="Tags"></BinaryString>
  1895. </Properties>
  1896. </Item>
  1897. <Item class="ModuleScript" referent="RBXB384619ED8DC4797ADD5027BCB9C2BB9">
  1898. <Properties>
  1899. <Content name="LinkedSource"><null></null></Content>
  1900. <string name="Name">Duration</string>
  1901. <string name="ScriptGuid">{4FEC71D5-1572-4BCD-AD82-065C6B1CF2B7}</string>
  1902. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  1903. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  1904. -- @source https://github.com/evaera/Cmdr
  1905. -- @rostrap Cmdr
  1906. -- @author evaera
  1907.  
  1908. local Util = require(script.Parent.Parent.Shared.Util)
  1909.  
  1910. local unitTable = {
  1911. Years = 31556926,
  1912. Months = 2629744,
  1913. Weeks = 604800,
  1914. Days = 86400,
  1915. Hours = 3600,
  1916. Minutes = 60,
  1917. Seconds = 1
  1918. }
  1919.  
  1920. local searchKeyTable = {}
  1921. for key, _ in pairs(unitTable) do
  1922. table.insert(searchKeyTable, key)
  1923. end
  1924. local unitFinder = Util.MakeFuzzyFinder(searchKeyTable)
  1925.  
  1926. local function stringToSecondDuration(stringDuration)
  1927. -- The duration cannot be null or an empty string.
  1928. if stringDuration == nil or stringDuration == "" then
  1929. return nil
  1930. end
  1931. -- Allow 0 by itself (without a unit) to indicate 0 seconds
  1932. local durationNum = tonumber(stringDuration)
  1933. if durationNum and durationNum == 0 then
  1934. return 0, 0, true
  1935. end
  1936. -- The duration must end with a unit,
  1937. -- if it doesn't then return true as the fourth value to indicate the need to offer autocomplete for units.
  1938. local endOnlyString = stringDuration:gsub("%d+%a+", "")
  1939. local endNumber = endOnlyString:match("%d+")
  1940. if endNumber then
  1941. return nil, tonumber(endNumber), true
  1942. end
  1943. local seconds = nil
  1944. local rawNum, rawUnit
  1945. for rawComponent in stringDuration:gmatch("%d+%a+") do
  1946. rawNum, rawUnit = rawComponent:match("(%d+)(%a+)")
  1947. local unitNames = unitFinder(rawUnit)
  1948. -- There were no matching units, it's invalid. Return the parsed number to be used for autocomplete
  1949. if #unitNames == 0 then
  1950. return nil, tonumber(rawNum)
  1951. end
  1952. if seconds == nil then seconds = 0 end
  1953. -- While it was already defaulting to use minutes when using just "m", this does it without worrying
  1954. -- about any consistency between list ordering.
  1955. seconds = seconds + (rawUnit:lower() == "m" and 60 or unitTable[unitNames[1]]) * tonumber(rawNum)
  1956. end
  1957. -- If no durations were provided, return nil.
  1958. if seconds == nil then
  1959. return nil
  1960. else
  1961. return seconds, tonumber(rawNum)
  1962. end
  1963. end
  1964.  
  1965. local function mapUnits(units, rawText, lastNumber, subStart)
  1966. subStart = subStart or 1
  1967. local returnTable = {}
  1968. for i, unit in pairs(units) do
  1969. if lastNumber == 1 then
  1970. returnTable[i] = rawText .. unit:sub(subStart, #unit - 1)
  1971. else
  1972. returnTable[i] = rawText .. unit:sub(subStart)
  1973. end
  1974. end
  1975. return returnTable
  1976. end
  1977.  
  1978. local durationType = {
  1979. Transform = function(text)
  1980. return text, stringToSecondDuration(text)
  1981. end;
  1982.  
  1983. Validate = function(_, duration)
  1984. return duration ~= nil and duration >= 0
  1985. end;
  1986.  
  1987. Autocomplete = function(rawText, duration, lastNumber, isUnitMissing, matchedUnits)
  1988. local returnTable = {}
  1989. if isUnitMissing or matchedUnits then
  1990. local unitsTable = isUnitMissing == true and unitFinder("") or matchedUnits
  1991. if isUnitMissing == true then
  1992. -- Concat the entire unit name to existing text.
  1993. returnTable = mapUnits(unitsTable, rawText, lastNumber)
  1994. else
  1995. -- Concat the rest of the unit based on what already exists of the unit name.
  1996. local existingUnitLength = rawText:match("^.*(%a+)$"):len()
  1997. returnTable = mapUnits(unitsTable, rawText, existingUnitLength + 1)
  1998. end
  1999. elseif duration ~= nil then
  2000. local endingUnit = rawText:match("^.*%d+(%a+)$")
  2001. -- Assume there is a singular match at this point
  2002. local fuzzyUnits = unitFinder(endingUnit)
  2003. -- List all possible fuzzy matches. This is for the Minutes/Months ambiguity case.
  2004. returnTable = mapUnits(fuzzyUnits, rawText, lastNumber, #endingUnit + 1)
  2005. -- Sort alphabetically in the Minutes/Months case, so Minutes are displayed on top.
  2006. table.sort(returnTable)
  2007. end
  2008. return returnTable
  2009. end;
  2010.  
  2011. Parse = function(_, duration)
  2012. return duration
  2013. end;
  2014. }
  2015.  
  2016. return function(registry)
  2017. registry:RegisterType("duration", durationType)
  2018. registry:RegisterType("durations", Util.MakeListableType(durationType))
  2019. end]]></ProtectedString>
  2020. <BinaryString name="Tags"></BinaryString>
  2021. </Properties>
  2022. </Item>
  2023. <Item class="ModuleScript" referent="RBX599092F54B544F07B2AF0198C9DED4A4">
  2024. <Properties>
  2025. <Content name="LinkedSource"><null></null></Content>
  2026. <string name="Name">Player</string>
  2027. <string name="ScriptGuid">{43961925-6FC1-4F63-A525-6091F7E2A05D}</string>
  2028. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  2029. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  2030. -- @source https://github.com/evaera/Cmdr
  2031. -- @rostrap Cmdr
  2032. -- @author evaera
  2033.  
  2034. local Util = require(script.Parent.Parent.Shared.Util)
  2035. local Players = game:GetService("Players")
  2036.  
  2037. local function ShorthandSingle (text, executor)
  2038. if text == "." or text == "me" then
  2039. return {executor}
  2040. end
  2041. end
  2042.  
  2043. local function ShorthandMultiple (text, executor)
  2044. if text == "*" or text == "all" then
  2045. return Players:GetPlayers()
  2046. elseif text == "others" then
  2047. local Others = Players:GetPlayers()
  2048. for i = 1, #Others do
  2049. if Others[i] == executor then
  2050. table.remove(Others, i)
  2051. break
  2052. end
  2053. end
  2054. return Others
  2055. end
  2056. end
  2057.  
  2058. local function CheckShorthands (text, executor, ...)
  2059. for _, func in pairs({...}) do
  2060. local values = func(text, executor)
  2061.  
  2062. if values then return values end
  2063. end
  2064. end
  2065.  
  2066. local playerType = {
  2067. Transform = function (text, executor)
  2068. local shorthand = CheckShorthands(text, executor, ShorthandSingle)
  2069. if shorthand then
  2070. return shorthand
  2071. end
  2072.  
  2073. local findPlayer = Util.MakeFuzzyFinder(Players:GetPlayers())
  2074.  
  2075. return findPlayer(text)
  2076. end;
  2077.  
  2078. Validate = function (players)
  2079. return #players > 0, "No player with that name could be found."
  2080. end;
  2081.  
  2082. Autocomplete = function (players)
  2083. return Util.GetNames(players)
  2084. end;
  2085.  
  2086. Parse = function (players)
  2087. return players[1]
  2088. end;
  2089. }
  2090.  
  2091. local playersType = {
  2092. Listable = true;
  2093.  
  2094. Transform = function (text, executor)
  2095. local shorthand = CheckShorthands(text, executor, ShorthandSingle, ShorthandMultiple)
  2096.  
  2097. if shorthand then
  2098. return shorthand, true
  2099. end
  2100.  
  2101. local findPlayers = Util.MakeFuzzyFinder(Players:GetPlayers())
  2102.  
  2103. return findPlayers(text)
  2104. end;
  2105.  
  2106. Validate = function (players)
  2107. return #players > 0, "No players were found matching that query."
  2108. end;
  2109.  
  2110. Autocomplete = function (players)
  2111. return Util.GetNames(players)
  2112. end;
  2113.  
  2114. Parse = function (players, returnAll)
  2115. return returnAll and players or { players[1] }
  2116. end;
  2117. }
  2118.  
  2119. return function (cmdr)
  2120. cmdr:RegisterType("player", playerType)
  2121. cmdr:RegisterType("players", playersType)
  2122. end
  2123. ]]></ProtectedString>
  2124. <BinaryString name="Tags"></BinaryString>
  2125. </Properties>
  2126. </Item>
  2127. <Item class="ModuleScript" referent="RBXBDDBF036BDA048DF819154E24AFF6EEE">
  2128. <Properties>
  2129. <Content name="LinkedSource"><null></null></Content>
  2130. <string name="Name">PlayerId</string>
  2131. <string name="ScriptGuid">{733AD56E-6BD0-41EE-9E46-62442F9E8755}</string>
  2132. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  2133. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  2134. -- @source https://github.com/evaera/Cmdr
  2135. -- @rostrap Cmdr
  2136. -- @author evaera
  2137.  
  2138. local Util = require(script.Parent.Parent.Shared.Util)
  2139. local Players = game:GetService("Players")
  2140.  
  2141. local nameCache = {}
  2142. local function getUserId(name)
  2143. if nameCache[name] then
  2144. return nameCache[name]
  2145. elseif Players:FindFirstChild(name) then
  2146. nameCache[name] = Players[name].UserId
  2147. return Players[name].UserId
  2148. else
  2149. local ok, userid = pcall(Players.GetUserIdFromNameAsync, Players, name)
  2150.  
  2151. if not ok then
  2152. return nil
  2153. end
  2154.  
  2155. nameCache[name] = userid
  2156. return userid
  2157. end
  2158. end
  2159.  
  2160. local playerIdType = {
  2161. DisplayName = "Full Player Name";
  2162.  
  2163. Transform = function (text)
  2164. local findPlayer = Util.MakeFuzzyFinder(Players:GetPlayers())
  2165.  
  2166. return text, findPlayer(text)
  2167. end;
  2168.  
  2169. ValidateOnce = function (text)
  2170. return getUserId(text) ~= nil, "No player with that name could be found."
  2171. end;
  2172.  
  2173. Autocomplete = function (_, players)
  2174. return Util.GetNames(players)
  2175. end;
  2176.  
  2177. Parse = function (text)
  2178. return getUserId(text)
  2179. end;
  2180. }
  2181.  
  2182. return function (cmdr)
  2183. cmdr:RegisterType("playerId", playerIdType)
  2184. cmdr:RegisterType("playerIds", Util.MakeListableType(playerIdType))
  2185. end
  2186. ]]></ProtectedString>
  2187. <BinaryString name="Tags"></BinaryString>
  2188. </Properties>
  2189. </Item>
  2190. <Item class="ModuleScript" referent="RBX13B272783ADA4E12A46B93254E029747">
  2191. <Properties>
  2192. <Content name="LinkedSource"><null></null></Content>
  2193. <string name="Name">Primitives</string>
  2194. <string name="ScriptGuid">{CD355608-E8F5-40F8-A24F-642072874529}</string>
  2195. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  2196. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  2197. -- @source https://github.com/evaera/Cmdr
  2198. -- @rostrap Cmdr
  2199. -- @author evaera
  2200.  
  2201. local Util = require(script.Parent.Parent.Shared.Util)
  2202.  
  2203. local stringType = {
  2204. Validate = function (value)
  2205. return value ~= nil
  2206. end;
  2207.  
  2208. Parse = function (value)
  2209. return tostring(value)
  2210. end;
  2211. }
  2212.  
  2213. local numberType = {
  2214. Transform = function (text)
  2215. return tonumber(text)
  2216. end;
  2217.  
  2218. Validate = function (value)
  2219. return value ~= nil
  2220. end;
  2221.  
  2222. Parse = function (value)
  2223. return value
  2224. end;
  2225. }
  2226.  
  2227. local intType = {
  2228. Transform = function (text)
  2229. return tonumber(text)
  2230. end;
  2231.  
  2232. Validate = function (value)
  2233. return value ~= nil and value == math.floor(value), "Only whole numbers are valid."
  2234. end;
  2235.  
  2236. Parse = function (value)
  2237. return value
  2238. end
  2239. }
  2240.  
  2241. local boolType do
  2242. local truthy = Util.MakeDictionary({"true", "t", "yes", "y", "on", "enable", "enabled", "1", "+"});
  2243. local falsy = Util.MakeDictionary({"false"; "f"; "no"; "n"; "off"; "disable"; "disabled"; "0"; "-"});
  2244.  
  2245. boolType = {
  2246. Transform = function (text)
  2247. return text:lower()
  2248. end;
  2249.  
  2250. Validate = function (value)
  2251. return truthy[value] ~= nil or falsy[value] ~= nil, "Please use true/yes/on or false/no/off."
  2252. end;
  2253.  
  2254. Parse = function (value)
  2255. if truthy[value] then
  2256. return true
  2257. elseif falsy[value] then
  2258. return false
  2259. else
  2260. error("Unknown boolean value.")
  2261. end
  2262. end;
  2263. }
  2264. end
  2265.  
  2266. return function (cmdr)
  2267. cmdr:RegisterType("string", stringType)
  2268. cmdr:RegisterType("number", numberType)
  2269. cmdr:RegisterType("integer", intType)
  2270. cmdr:RegisterType("boolean", boolType)
  2271.  
  2272. cmdr:RegisterType("strings", Util.MakeListableType(stringType))
  2273. cmdr:RegisterType("numbers", Util.MakeListableType(numberType))
  2274. cmdr:RegisterType("integers", Util.MakeListableType(intType))
  2275. cmdr:RegisterType("booleans", Util.MakeListableType(boolType))
  2276. end]]></ProtectedString>
  2277. <BinaryString name="Tags"></BinaryString>
  2278. </Properties>
  2279. </Item>
  2280. <Item class="ModuleScript" referent="RBXF471B0EAB54240449D47116CA22DF7D8">
  2281. <Properties>
  2282. <Content name="LinkedSource"><null></null></Content>
  2283. <string name="Name">Team</string>
  2284. <string name="ScriptGuid">{98D7A448-55AD-449B-A978-20528E3CF220}</string>
  2285. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  2286. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  2287. -- @source https://github.com/evaera/Cmdr
  2288. -- @rostrap Cmdr
  2289. -- @author evaera
  2290.  
  2291. local Teams = game:GetService("Teams")
  2292. local Util = require(script.Parent.Parent.Shared.Util)
  2293.  
  2294. local teamType = {
  2295. Transform = function (text)
  2296. local findTeam = Util.MakeFuzzyFinder(Teams:GetTeams())
  2297.  
  2298. return findTeam(text)
  2299. end;
  2300.  
  2301. Validate = function (teams)
  2302. return #teams > 0, "No team with that name could be found."
  2303. end;
  2304.  
  2305. Autocomplete = function (teams)
  2306. return Util.GetNames(teams)
  2307. end;
  2308.  
  2309. Parse = function (teams)
  2310. return teams[1];
  2311. end;
  2312. }
  2313.  
  2314. local teamPlayersType = {
  2315. Listable = true;
  2316. Transform = teamType.Transform;
  2317. Validate = teamType.Validate;
  2318. Autocomplete = teamType.Autocomplete;
  2319.  
  2320. Parse = function (teams)
  2321. return teams[1]:GetPlayers()
  2322. end;
  2323. }
  2324.  
  2325. local teamColorType = {
  2326. Transform = teamType.Transform;
  2327. Validate = teamType.Validate;
  2328. Autocomplete = teamType.Autocomplete;
  2329.  
  2330. Parse = function (teams)
  2331. return teams[1].TeamColor
  2332. end;
  2333. }
  2334.  
  2335. return function (cmdr)
  2336. cmdr:RegisterType("team", teamType)
  2337. cmdr:RegisterType("teams", Util.MakeListableType(teamType))
  2338.  
  2339. cmdr:RegisterType("teamPlayers", teamPlayersType)
  2340.  
  2341. cmdr:RegisterType("teamColor", teamColorType)
  2342. cmdr:RegisterType("teamColors", Util.MakeListableType(teamColorType))
  2343. end]]></ProtectedString>
  2344. <BinaryString name="Tags"></BinaryString>
  2345. </Properties>
  2346. </Item>
  2347. <Item class="ModuleScript" referent="RBX5B6895F0800A43ED98E1C88E3E931E76">
  2348. <Properties>
  2349. <Content name="LinkedSource"><null></null></Content>
  2350. <string name="Name">UserInput</string>
  2351. <string name="ScriptGuid">{1E4626B3-7A93-4BC8-A167-72EA55831D09}</string>
  2352. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  2353. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  2354. -- @source https://github.com/evaera/Cmdr
  2355. -- @rostrap Cmdr
  2356. -- @author evaera
  2357.  
  2358. local Util = require(script.Parent.Parent.Shared.Util)
  2359.  
  2360. local combinedInputEnums = Enum.UserInputType:GetEnumItems()
  2361.  
  2362. for _, e in pairs(Enum.KeyCode:GetEnumItems()) do
  2363. combinedInputEnums[#combinedInputEnums + 1] = e
  2364. end
  2365.  
  2366. local userInputType = {
  2367. Transform = function (text)
  2368. local findEnum = Util.MakeFuzzyFinder(combinedInputEnums)
  2369.  
  2370. return findEnum(text)
  2371. end;
  2372.  
  2373. Validate = function (enums)
  2374. return #enums > 0
  2375. end;
  2376.  
  2377. Autocomplete = function (enums)
  2378. return Util.GetNames(enums)
  2379. end;
  2380.  
  2381. Parse = function (enums)
  2382. return enums[1];
  2383. end;
  2384. }
  2385.  
  2386. return function (cmdr)
  2387. cmdr:RegisterType("userInput", userInputType)
  2388. cmdr:RegisterType("userInputs", Util.MakeListableType(userInputType))
  2389. end]]></ProtectedString>
  2390. <BinaryString name="Tags"></BinaryString>
  2391. </Properties>
  2392. </Item>
  2393. <Item class="ModuleScript" referent="RBX2EA11A3AD0BD440096D0A01F152534F2">
  2394. <Properties>
  2395. <Content name="LinkedSource"><null></null></Content>
  2396. <string name="Name">Vector</string>
  2397. <string name="ScriptGuid">{BF85AE9A-0FBE-4EAA-98CF-F55AC02BA9FA}</string>
  2398. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  2399. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  2400. -- @source https://github.com/evaera/Cmdr
  2401. -- @rostrap Cmdr
  2402. -- @author evaera
  2403.  
  2404. local Util = require(script.Parent.Parent.Shared.Util)
  2405.  
  2406. local function validateVector(value, i)
  2407. if value == nil then
  2408. return false, ("Invalid or missing number at position %d in Vector type."):format(i)
  2409. end
  2410.  
  2411. return true
  2412. end
  2413.  
  2414. local vector3Type = Util.MakeSequenceType({
  2415. ValidateEach = validateVector;
  2416. TransformEach = tonumber;
  2417. Constructor = Vector3.new;
  2418. Length = 3;
  2419. })
  2420.  
  2421. local vector2Type = Util.MakeSequenceType({
  2422. ValidateEach = validateVector;
  2423. TransformEach = tonumber;
  2424. Constructor = Vector2.new;
  2425. Length = 2;
  2426. })
  2427.  
  2428. return function (cmdr)
  2429. cmdr:RegisterType("vector3", vector3Type)
  2430. cmdr:RegisterType("vector3s", Util.MakeListableType(vector3Type))
  2431.  
  2432. cmdr:RegisterType("vector2", vector2Type)
  2433. cmdr:RegisterType("vector2s", Util.MakeListableType(vector2Type))
  2434. end]]></ProtectedString>
  2435. <BinaryString name="Tags"></BinaryString>
  2436. </Properties>
  2437. </Item>
  2438. </Item>
  2439. <Item class="Folder" referent="RBX66A52AFF88594D1AB194C4A00314A929">
  2440. <Properties>
  2441. <string name="Name">Shared</string>
  2442. <BinaryString name="Tags"></BinaryString>
  2443. </Properties>
  2444. <Item class="ModuleScript" referent="RBX716C459E6F0242A195AA74E318076C2B">
  2445. <Properties>
  2446. <Content name="LinkedSource"><null></null></Content>
  2447. <string name="Name">Argument</string>
  2448. <string name="ScriptGuid">{27B50999-F950-4357-B8AA-3E602A18E479}</string>
  2449. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  2450. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  2451. -- @source https://github.com/evaera/Cmdr
  2452. -- @rostrap Cmdr
  2453. -- @author evaera
  2454.  
  2455. local TYPE_DEFAULTS = {
  2456. -- Make all `players` types also be able to match by team
  2457. players = "players % teamPlayers";
  2458.  
  2459. playerId = "playerId # integer";
  2460. playerIds = "playerIds # integers";
  2461.  
  2462. brickColor = "brickColor % teamColor";
  2463. brickColors = "brickColors % teamColors";
  2464.  
  2465. color3 = "color3 # hexColor3 ! brickColor3";
  2466. color3s = "color3s # hexColor3s ! brickColor3s";
  2467. }
  2468.  
  2469. local Util = require(script.Parent.Util)
  2470.  
  2471. local Argument = {}
  2472. Argument.__index = Argument
  2473.  
  2474. --- Returns a new ArgumentContext, an object that handles parsing and validating arguments
  2475. function Argument.new (command, argumentObject, value)
  2476. local self = {
  2477. Command = command; -- The command that owns this argument
  2478. Type = nil; -- The type definition
  2479. Name = argumentObject.Name; -- The name for this specific argument
  2480. Object = argumentObject; -- The raw ArgumentObject (definition)
  2481. Required = argumentObject.Default == nil and argumentObject.Optional ~= true; -- If the argument is required or not.
  2482. Executor = command.Executor; -- The player who is running the command
  2483. RawValue = nil; -- The raw, unparsed value
  2484. RawSegments = {}; -- The raw, unparsed segments (if the raw value was comma-sep)
  2485. TransformedValues = {}; -- The transformed value (generated later)
  2486. Prefix = nil; -- The prefix for this command (%Team)
  2487. }
  2488.  
  2489. local parsedType, parsedRawValue, prefix = Util.ParsePrefixedUnionType(
  2490. TYPE_DEFAULTS[argumentObject.Type] or argumentObject.Type, value
  2491. )
  2492.  
  2493. self.Type = command.Dispatcher.Registry:GetType(parsedType)
  2494. self.RawValue = parsedRawValue
  2495. self.Prefix = prefix
  2496.  
  2497. if self.Type == nil then
  2498. error(string.format("%s has an unregistered type %q", self.Name or "<none>", parsedType or "<none>"))
  2499. end
  2500.  
  2501. setmetatable(self, Argument)
  2502.  
  2503. self:Transform()
  2504.  
  2505. return self
  2506. end
  2507.  
  2508. --- Calls the transform function on this argument.
  2509. -- The return value(s) from this function are passed to all of the other argument methods.
  2510. -- Called automatically at instantiation
  2511. function Argument:Transform()
  2512. if #self.TransformedValues ~= 0 then
  2513. return
  2514. end
  2515.  
  2516. if self.Type.Listable and #self.RawValue > 0 then
  2517. local rawSegments = Util.SplitStringSimple(self.RawValue, ",")
  2518.  
  2519. if self.RawValue:sub(#self.RawValue, #self.RawValue) == "," then
  2520. rawSegments[#rawSegments + 1] = "" -- makes auto complete tick over right after pressing ,
  2521. end
  2522.  
  2523. for i, rawSegment in ipairs(rawSegments) do
  2524. self.RawSegments[i] = rawSegment
  2525. self.TransformedValues[i] = { self:TransformSegment(rawSegment) }
  2526. end
  2527. else
  2528. self.RawSegments[1] = self.RawValue
  2529. self.TransformedValues[1] = { self:TransformSegment(self.RawValue) }
  2530. end
  2531. end
  2532.  
  2533. function Argument:TransformSegment(rawSegment)
  2534. if self.Type.Transform then
  2535. return self.Type.Transform(rawSegment, self.Executor)
  2536. else
  2537. return rawSegment
  2538. end
  2539. end
  2540.  
  2541. --- Returns whatever the Transform method gave us.
  2542. function Argument:GetTransformedValue(segment)
  2543. return unpack(self.TransformedValues[segment])
  2544. end
  2545.  
  2546. --- Validates that the argument will work without any type errors.
  2547. function Argument:Validate(isFinal)
  2548. if self.RawValue == nil or #self.RawValue == 0 and self.Required == false then
  2549. return true
  2550. end
  2551.  
  2552. if self.Type.Validate or self.Type.ValidateOnce then
  2553. for i = 1, #self.TransformedValues do
  2554. if self.Type.Validate then
  2555. local valid, errorText = self.Type.Validate(self:GetTransformedValue(i))
  2556.  
  2557. if not valid then
  2558. return valid, errorText or "Invalid value"
  2559. end
  2560. end
  2561.  
  2562. if isFinal and self.Type.ValidateOnce then
  2563. local validOnce, errorTextOnce = self.Type.ValidateOnce(self:GetTransformedValue(i))
  2564.  
  2565. if not validOnce then
  2566. return validOnce, errorTextOnce
  2567. end
  2568. end
  2569. end
  2570.  
  2571. return true
  2572. else
  2573. return true
  2574. end
  2575. end
  2576.  
  2577. --- Gets a list of all possible values that could match based on the current value.
  2578. function Argument:GetAutocomplete()
  2579. if self.Type.Autocomplete then
  2580. return self.Type.Autocomplete(self:GetTransformedValue(#self.TransformedValues))
  2581. else
  2582. return {}
  2583. end
  2584. end
  2585.  
  2586. function Argument:ParseValue(i)
  2587. if self.Type.Parse then
  2588. return self.Type.Parse(self:GetTransformedValue(i))
  2589. else
  2590. return self:GetTransformedValue(i)
  2591. end
  2592. end
  2593.  
  2594. --- Returns the final value of the argument.
  2595. function Argument:GetValue()
  2596. if #self.RawValue == 0 and not self.Required and self.Object.Default ~= nil then
  2597. return self.Object.Default
  2598. end
  2599.  
  2600. if not self.Type.Listable then
  2601. return self:ParseValue(1)
  2602. end
  2603.  
  2604. local values = {}
  2605.  
  2606. for i = 1, #self.TransformedValues do
  2607. local parsedValue = self:ParseValue(i)
  2608.  
  2609. if type(parsedValue) ~= "table" then
  2610. error(("Listable types must return a table from Parse (%s)"):format(self.Type.Name))
  2611. end
  2612.  
  2613. for _, value in pairs(parsedValue) do
  2614. values[value] = true -- Put them into a dictionary to ensure uniqueness
  2615. end
  2616. end
  2617.  
  2618. local valueArray = {}
  2619.  
  2620. for value in pairs(values) do
  2621. valueArray[#valueArray + 1] = value
  2622. end
  2623.  
  2624. return valueArray
  2625. end
  2626.  
  2627. return Argument]]></ProtectedString>
  2628. <BinaryString name="Tags"></BinaryString>
  2629. </Properties>
  2630. </Item>
  2631. <Item class="ModuleScript" referent="RBX11E9EB676C274EDEA8E7B702715FF9C7">
  2632. <Properties>
  2633. <Content name="LinkedSource"><null></null></Content>
  2634. <string name="Name">Command</string>
  2635. <string name="ScriptGuid">{87DF3A9B-052B-4922-A962-9C737324A21F}</string>
  2636. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  2637. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  2638. -- @source https://github.com/evaera/Cmdr
  2639. -- @rostrap Cmdr
  2640. -- @author evaera
  2641.  
  2642. local RunService = game:GetService("RunService")
  2643. local Players = game:GetService("Players")
  2644. local Argument = require(script.Parent.Argument)
  2645.  
  2646. local IsServer = RunService:IsServer()
  2647.  
  2648. local Command = {}
  2649. Command.__index = Command
  2650.  
  2651. --- Returns a new CommandContext, an object which is created for every command validation.
  2652. -- This is also what's passed as the context to the "Run" functions in commands
  2653. function Command.new (options)
  2654. local self = {
  2655. Dispatcher = options.Dispatcher; -- The dispatcher that created this command context
  2656. Cmdr = options.Dispatcher.Cmdr; -- A quick reference to Cmdr for command context
  2657. Name = options.CommandObject.Name; -- The command name (not alias)
  2658. RawText = options.Text; -- The raw text used to trigger this command
  2659. Object = options.CommandObject; -- The command object (definition)
  2660. Group = options.CommandObject.Group; -- The group this command is in
  2661. State = {}; -- A table which will hold any custom command state information
  2662. Aliases = options.CommandObject.Aliases;
  2663. Alias = options.Alias; -- The command name that was used
  2664. Description = options.CommandObject.Description;
  2665. Executor = options.Executor; -- The player who ran the command
  2666. ArgumentDefinitions = options.CommandObject.Args; -- The argument definitions from the command definition
  2667. RawArguments = options.Arguments; -- Array of strings which are the unparsed values for the arguments
  2668. Arguments = {}; -- A table which will hold ArgumentContexts for each argument
  2669. Data = options.Data; -- A special container for any additional data the command needs to collect from the client
  2670. Response = nil; -- Will be set at the very end when the command is run and a string is returned from the Run function.
  2671. }
  2672.  
  2673. setmetatable(self, Command)
  2674.  
  2675. return self
  2676. end
  2677.  
  2678. --- Parses all of the command arguments into ArgumentContexts
  2679. -- Called by the command dispatcher automatically
  2680. -- allowIncompleteArguments: if true, will not throw an error for missing arguments
  2681. function Command:Parse (allowIncompleteArguments)
  2682. local hadOptional = false
  2683. for i, definition in ipairs(self.ArgumentDefinitions) do
  2684. local required = (definition.Default == nil and definition.Optional ~= true)
  2685.  
  2686. if required and hadOptional then
  2687. error(("Command %q: Required arguments cannot occur after optional arguments."):format(self.Name))
  2688. elseif not required then
  2689. hadOptional = true
  2690. end
  2691.  
  2692. if self.RawArguments[i] == nil and required and allowIncompleteArguments ~= true then
  2693. return false, ("Required argument #%d %s is missing."):format(i, definition.Name)
  2694. elseif self.RawArguments[i] or allowIncompleteArguments then
  2695. self.Arguments[i] = Argument.new(self, definition, self.RawArguments[i] or "")
  2696. end
  2697. end
  2698.  
  2699. return true
  2700. end
  2701.  
  2702. --- Validates that all of the arguments are in a valid state.
  2703. -- This must be called before :Run() is called.
  2704. -- Returns boolean (true if ok), errorText
  2705. function Command:Validate (isFinal)
  2706. self._Validated = true
  2707. local errorText = ""
  2708. local success = true
  2709.  
  2710. for i, arg in pairs(self.Arguments) do
  2711. local argSuccess, argErrorText = arg:Validate(isFinal)
  2712.  
  2713. if not argSuccess then
  2714. success = false
  2715. errorText = ("%s; #%d %s: %s"):format(errorText, i, arg.Name, argErrorText or "error")
  2716. end
  2717. end
  2718.  
  2719. return success, errorText:sub(3)
  2720. end
  2721.  
  2722. --- Returns the last argument that has a value.
  2723. -- Useful for getting the autocomplete for the argument the user is working on.
  2724. function Command:GetLastArgument()
  2725. for i = #self.Arguments, 1, -1 do
  2726. if self.Arguments[i].RawValue then
  2727. return self.Arguments[i]
  2728. end
  2729. end
  2730. end
  2731.  
  2732. --- Returns a table containing the parsed values for all of the arguments.
  2733. function Command:GatherArgumentValues ()
  2734. local values = {}
  2735.  
  2736. for i = 1, #self.ArgumentDefinitions do
  2737. local arg = self.Arguments[i]
  2738. if arg then
  2739. values[i] = arg:GetValue()
  2740. else
  2741. values[i] = self.ArgumentDefinitions[i].Default
  2742. end
  2743. end
  2744.  
  2745. return values
  2746. end
  2747.  
  2748. --- Runs the command. Handles dispatching to the server if necessary.
  2749. -- Command:Validate() must be called before this is called or it will throw.
  2750. function Command:Run ()
  2751. if self._Validated == nil then
  2752. error("Must validate a command before running.")
  2753. end
  2754.  
  2755. local beforeRunHook = self.Dispatcher:RunHooks("BeforeRun", self)
  2756. if beforeRunHook then
  2757. return beforeRunHook
  2758. end
  2759.  
  2760. if self.Object.Run then -- We can just Run it here on this machine
  2761. self.Response = self.Object.Run(self, unpack(self:GatherArgumentValues()))
  2762. elseif IsServer then -- Uh oh, we're already on the server and there's no Run function.
  2763. warn(self.Name, "command has no implementation!")
  2764. self.Response = "No implementation."
  2765. else -- We're on the client, so we send this off to the server to let the server see what it can do with it.
  2766. self.Response = self.Dispatcher:Send(self.RawText, self.Object.Data and self.Object.Data(self))
  2767. end
  2768.  
  2769. local afterRunHook = self.Dispatcher:RunHooks("AfterRun", self)
  2770. if afterRunHook then
  2771. return afterRunHook
  2772. else
  2773. return self.Response
  2774. end
  2775. end
  2776.  
  2777. --- Returns an ArgumentContext for the specific index
  2778. function Command:GetArgument (index)
  2779. return self.Arguments[index]
  2780. end
  2781.  
  2782. -- Below are functions that are only meant to be used in command implementations --
  2783.  
  2784. --- Returns the extra data associated with this command.
  2785. -- This needs to be used instead of just context.Data for reliability when not using a remote command.
  2786. function Command:GetData ()
  2787. if self.Data then
  2788. return self.Data
  2789. end
  2790.  
  2791. if self.Object.Data and not IsServer then
  2792. self.Data = self.Object.Data(self)
  2793. end
  2794.  
  2795. return self.Data
  2796. end
  2797.  
  2798. --- Sends an event message to a player
  2799. function Command:SendEvent(player, event, ...)
  2800. assert(typeof(player) == "Instance", "Argument #1 must be a Player")
  2801. assert(player:IsA("Player"), "Argument #1 must be a Player")
  2802. assert(type(event) == "string", "Argument #2 must be a string")
  2803.  
  2804. if IsServer then
  2805. self.Dispatcher.Cmdr.RemoteEvent:FireClient(player, event, ...)
  2806. elseif self.Dispatcher.Cmdr.Events[event] then
  2807. assert(player == Players.LocalPlayer, "Event messages can only be sent to the local player on the client.")
  2808. self.Dispatcher.Cmdr.Events[event](...)
  2809. end
  2810. end
  2811.  
  2812. --- Sends an event message to all players
  2813. function Command:BroadcastEvent(...)
  2814. if not IsServer then
  2815. error("Can't broadcast event messages from the client.", 2)
  2816. end
  2817.  
  2818. self.Dispatcher.Cmdr.RemoteEvent:FireAllClients(...)
  2819. end
  2820.  
  2821. --- Alias of self:SendEvent(self.Executor, "AddLine", text)
  2822. function Command:Reply(...)
  2823. return self:SendEvent(self.Executor, "AddLine", ...)
  2824. end
  2825.  
  2826. --- Alias of Registry:GetStore(...)
  2827. function Command:GetStore(...)
  2828. return self.Dispatcher.Cmdr.Registry:GetStore(...)
  2829. end
  2830.  
  2831. return Command
  2832. ]]></ProtectedString>
  2833. <BinaryString name="Tags"></BinaryString>
  2834. </Properties>
  2835. </Item>
  2836. <Item class="ModuleScript" referent="RBX605C1FBC658B4EA8B3572B11FD05647A">
  2837. <Properties>
  2838. <Content name="LinkedSource"><null></null></Content>
  2839. <string name="Name">Dispatcher</string>
  2840. <string name="ScriptGuid">{7F66E598-3579-48FA-A96F-7321D43FDDEE}</string>
  2841. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  2842. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  2843. -- @source https://github.com/evaera/Cmdr
  2844. -- @rostrap Cmdr
  2845. -- @author evaera
  2846.  
  2847. local RunService = game:GetService("RunService")
  2848. local TeleportService = game:GetService("TeleportService")
  2849. local Players = game:GetService("Players")
  2850. local Util = require(script.Parent.Util)
  2851. local Command = require(script.Parent.Command)
  2852.  
  2853. local HISTORY_SETTING_NAME = "CmdrCommandHistory"
  2854.  
  2855. --- The dispatcher handles creating and running commands during the game.
  2856. local Dispatcher = {
  2857. Cmdr = nil;
  2858. Registry = nil;
  2859.  
  2860. }
  2861.  
  2862. --- Takes in raw command information and generates a command out of it.
  2863. -- text and executor are required arguments.
  2864. -- allowIncompleteData, when true, will ignore errors about arguments missing so we can parse live as the user types.
  2865. -- data is for special networked Data about the command gathered on the client. Purely Optional.
  2866. -- returns the command if successful, or (false, errorText) if not
  2867. function Dispatcher:Evaluate (text, executor, allowIncompleteArguments, data)
  2868. if RunService:IsClient() == true and executor ~= Players.LocalPlayer then
  2869. error("Can't evaluate a command that isn't sent by the local player.")
  2870. end
  2871.  
  2872. local arguments = Util.SplitString(text)
  2873. local commandName = table.remove(arguments, 1)
  2874. local commandObject = self.Registry:GetCommand(commandName)
  2875.  
  2876. if commandObject then
  2877. -- No need to continue splitting when there are no more arguments. We'll just mash any additional arguments into the last one.
  2878. arguments = Util.MashExcessArguments(arguments, #commandObject.Args)
  2879.  
  2880. -- Create the CommandContext and parse it.
  2881. local command = Command.new({
  2882. Dispatcher = self,
  2883. Text = text,
  2884. CommandObject = commandObject,
  2885. Alias = commandName,
  2886. Executor = executor,
  2887. Arguments = arguments,
  2888. Data = data
  2889. })
  2890. local success, errorText = command:Parse(allowIncompleteArguments)
  2891.  
  2892. if success then
  2893. return command
  2894. else
  2895. return false, errorText
  2896. end
  2897. else
  2898. return false, "Invalid command. Use the help command to see all available commands."
  2899. end
  2900. end
  2901.  
  2902. --- A helper that evaluates and runs the command in one go.
  2903. -- Either returns any validation errors as a string, or the output of the command as a string. Definitely a string, though.
  2904. function Dispatcher:EvaluateAndRun (text, executor, options)
  2905. executor = executor or Players.LocalPlayer
  2906. options = options or {}
  2907.  
  2908. if RunService:IsClient() and options.IsHuman then
  2909. self:PushHistory(text)
  2910. end
  2911.  
  2912. local command, errorText = self:Evaluate(text, executor, nil, options.Data)
  2913.  
  2914. if not command then
  2915. return errorText
  2916. end
  2917.  
  2918. local ok, out = pcall(function()
  2919. local valid, errorText = command:Validate(true) -- luacheck: ignore
  2920.  
  2921. if not valid then
  2922. return errorText
  2923. end
  2924.  
  2925. return command:Run() or "Command executed."
  2926. end)
  2927.  
  2928. if not ok then
  2929. warn(("Error occurred while evaluating command string %q\n%s"):format(text, out))
  2930. end
  2931.  
  2932. return ok and out or "An error occurred while running this command."
  2933. end
  2934.  
  2935. --- Send text as the local user to remote server to be evaluated there.
  2936. function Dispatcher:Send (text, data)
  2937. if RunService:IsClient() == false then
  2938. error("Dispatcher:Send can only be called from the client.")
  2939. end
  2940.  
  2941. return self.Cmdr.RemoteFunction:InvokeServer(text, {
  2942. Data = data
  2943. })
  2944. end
  2945.  
  2946. --- Invoke a command programmatically as the local user e.g. from a settings menu
  2947. -- Command should be the first argument, all arguments afterwards should be the arguments to the command.
  2948. function Dispatcher:Run (...)
  2949. if not Players.LocalPlayer then
  2950. error("Dispatcher:Run can only be called from the client.")
  2951. end
  2952.  
  2953. local args = {...}
  2954. local text = args[1]
  2955.  
  2956. for i = 2, #args do
  2957. text = text .. " " .. tostring(args[i])
  2958. end
  2959.  
  2960. local command, errorText = self:Evaluate(text, Players.LocalPlayer)
  2961.  
  2962. if not command then
  2963. error(errorText) -- We do a full-on error here since this is code-invoked and they should know better.
  2964. end
  2965.  
  2966. local success, errorText = command:Validate(true) -- luacheck: ignore
  2967.  
  2968. if not success then
  2969. error(errorText)
  2970. end
  2971.  
  2972. return command:Run()
  2973. end
  2974.  
  2975. --- Runs hooks matching name and returns nil for ok or a string for cancellation
  2976. function Dispatcher:RunHooks(hookName, ...)
  2977. if not self.Registry.Hooks[hookName] then
  2978. error(("Invalid hook name: %q"):format(hookName), 2)
  2979. end
  2980.  
  2981. for _, hook in ipairs(self.Registry.Hooks[hookName]) do
  2982. local value = hook.callback(...)
  2983.  
  2984. if value ~= nil then
  2985. return tostring(value)
  2986. end
  2987. end
  2988. end
  2989.  
  2990. function Dispatcher:PushHistory(text)
  2991. assert(RunService:IsClient(), "PushHistory may only be used from the client.")
  2992.  
  2993. local history = self:GetHistory()
  2994.  
  2995. -- Remove duplicates
  2996. if Util.TrimString(text) == "" or text == history[#history] then
  2997. return
  2998. end
  2999.  
  3000. history[#history + 1] = text
  3001.  
  3002. TeleportService:SetTeleportSetting(HISTORY_SETTING_NAME, history)
  3003. end
  3004.  
  3005. function Dispatcher:GetHistory()
  3006. assert(RunService:IsClient(), "GetHistory may only be used from the client.")
  3007.  
  3008. return TeleportService:GetTeleportSetting(HISTORY_SETTING_NAME) or {}
  3009. end
  3010.  
  3011. return function (cmdr)
  3012. Dispatcher.Cmdr = cmdr
  3013. Dispatcher.Registry = cmdr.Registry
  3014.  
  3015. return Dispatcher
  3016. end]]></ProtectedString>
  3017. <BinaryString name="Tags"></BinaryString>
  3018. </Properties>
  3019. </Item>
  3020. <Item class="ModuleScript" referent="RBXA013658904974BF49DB641C0A93175F4">
  3021. <Properties>
  3022. <Content name="LinkedSource"><null></null></Content>
  3023. <string name="Name">Registry</string>
  3024. <string name="ScriptGuid">{33D92E98-6382-4A3F-B9F7-7CDEC2031ED5}</string>
  3025. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  3026. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  3027. -- @source https://github.com/evaera/Cmdr
  3028. -- @rostrap Cmdr
  3029. -- @author evaera
  3030.  
  3031. local RunService = game:GetService("RunService")
  3032.  
  3033. local Util = require(script.Parent.Util)
  3034.  
  3035. --- The registry keeps track of all the commands and types that Cmdr knows about.
  3036. local Registry = {
  3037. TypeMethods = Util.MakeDictionary({"Transform", "Validate", "Autocomplete", "Parse", "DisplayName", "Listable", "ValidateOnce"});
  3038. CommandMethods = Util.MakeDictionary({"Name", "Aliases", "AutoExec", "Description", "Args", "Run", "Data", "Group"});
  3039. CommandArgProps = Util.MakeDictionary({"Name", "Type", "Description", "Optional", "Default"});
  3040. Types = {};
  3041. Commands = {};
  3042. CommandsArray = {};
  3043. Cmdr = nil;
  3044. Hooks = {
  3045. BeforeRun = {};
  3046. AfterRun = {}
  3047. };
  3048. Stores = setmetatable({}, {
  3049. __index = function (self, k)
  3050. self[k] = {}
  3051. return self[k]
  3052. end
  3053. });
  3054. AutoExecBuffer = {};
  3055. }
  3056.  
  3057. --- Registers a type in the system.
  3058. -- name: The type Name. This must be unique.
  3059. function Registry:RegisterType (name, typeObject)
  3060. if not name or not typeof(name) == "string" then
  3061. error("Invalid type name provided: nil")
  3062. end
  3063.  
  3064. if not name:find("^[%d%l]%w*$") then
  3065. error(('Invalid type name provided: "%s", type names must be alphanumeric and start with a lower-case letter or a digit.'):format(name))
  3066. end
  3067.  
  3068. for key in pairs(typeObject) do
  3069. if self.TypeMethods[key] == nil then
  3070. error("Unknown key/method in type \"" .. name .. "\": " .. key)
  3071. end
  3072. end
  3073.  
  3074. if self.Types[name] ~= nil then
  3075. error(('Type "%s" has already been registered.'):format(name))
  3076. end
  3077.  
  3078. typeObject.Name = name
  3079. typeObject.DisplayName = typeObject.DisplayName or name
  3080.  
  3081. self.Types[name] = typeObject
  3082. end
  3083.  
  3084. --- Helper method that registers types from all module scripts in a specific container.
  3085. function Registry:RegisterTypesIn (container)
  3086. for _, object in pairs(container:GetChildren()) do
  3087. if object:IsA("ModuleScript") then
  3088. object.Parent = self.Cmdr.ReplicatedRoot.Types
  3089.  
  3090. require(object)(self)
  3091. else
  3092. self:RegisterTypesIn(object)
  3093. end
  3094. end
  3095. end
  3096.  
  3097. -- These are exactly the same thing. No one will notice. Except for you, dear reader.
  3098. Registry.RegisterHooksIn = Registry.RegisterTypesIn
  3099.  
  3100. --- Registers a command based purely on its definition.
  3101. -- Prefer using Registry:RegisterCommand for proper handling of server/client model.
  3102. function Registry:RegisterCommandObject (commandObject)
  3103. for key in pairs(commandObject) do
  3104. if self.CommandMethods[key] == nil then
  3105. error("Unknown key/method in command " .. (commandObject.Name or "unknown command") .. ": " .. key)
  3106. end
  3107. end
  3108.  
  3109. if commandObject.Args then
  3110. for i, arg in pairs(commandObject.Args) do
  3111. for key in pairs(arg) do
  3112. if self.CommandArgProps[key] == nil then
  3113. error(('Unknown propery in command "%s" argument #%d: %s'):format(commandObject.Name or "unknown", i, key))
  3114. end
  3115. end
  3116. end
  3117. end
  3118.  
  3119. if RunService:IsClient() and commandObject.Data and commandObject.Run then
  3120. error(('Invalid command implementation provided for "%s": "Data" and "Run" sections are mutually exclusive'):format(commandObject.Name or "unknown"))
  3121. end
  3122.  
  3123. if commandObject.AutoExec and RunService:IsClient() then
  3124. table.insert(self.AutoExecBuffer, commandObject.AutoExec)
  3125. self:FlushAutoExecBufferDeferred()
  3126. end
  3127.  
  3128. -- Unregister the old command if it exists...
  3129. local oldCommand = self.Commands[commandObject.Name:lower()]
  3130. if oldCommand and oldCommand.Aliases then
  3131. for _, alias in pairs(oldCommand.Aliases) do
  3132. self.Commands[alias:lower()] = nil
  3133. end
  3134. elseif not oldCommand then
  3135. self.CommandsArray[#self.CommandsArray + 1] = commandObject
  3136. end
  3137.  
  3138. self.Commands[commandObject.Name:lower()] = commandObject
  3139.  
  3140. if commandObject.Aliases then
  3141. for _, alias in pairs(commandObject.Aliases) do
  3142. self.Commands[alias:lower()] = commandObject
  3143. end
  3144. end
  3145. end
  3146.  
  3147. --- Registers a command definition and its server equivalent.
  3148. -- Handles replicating the definition to the client.
  3149. function Registry:RegisterCommand (commandScript, commandServerScript, filter)
  3150. local commandObject = require(commandScript)
  3151.  
  3152. if commandServerScript then
  3153. commandObject.Run = require(commandServerScript)
  3154. end
  3155.  
  3156. if filter and not filter(commandObject) then
  3157. return
  3158. end
  3159.  
  3160. self:RegisterCommandObject(commandObject)
  3161.  
  3162. commandScript.Parent = self.Cmdr.ReplicatedRoot.Commands
  3163. end
  3164.  
  3165. --- A helper method that registers all commands inside a specific container.
  3166. function Registry:RegisterCommandsIn (container, filter)
  3167. local skippedServerScripts = {}
  3168. local usedServerScripts = {}
  3169.  
  3170. for _, commandScript in pairs(container:GetChildren()) do
  3171. if commandScript:IsA("ModuleScript") then
  3172. if not commandScript.Name:find("Server") then
  3173. local serverCommandScript = container:FindFirstChild(commandScript.Name .. "Server")
  3174.  
  3175. if serverCommandScript then
  3176. usedServerScripts[serverCommandScript] = true
  3177. end
  3178.  
  3179. self:RegisterCommand(commandScript, serverCommandScript, filter)
  3180. else
  3181. skippedServerScripts[commandScript] = true
  3182. end
  3183. else
  3184. self:RegisterCommandsIn(commandScript, filter)
  3185. end
  3186. end
  3187.  
  3188. for skippedScript in pairs(skippedServerScripts) do
  3189. if not usedServerScripts[skippedScript] then
  3190. warn("Command script " .. skippedScript.Name .. " was skipped because it has 'Server' in its name, and has no equivalent shared script.")
  3191. end
  3192. end
  3193. end
  3194.  
  3195. --- Registers the default commands, with an optional filter function or array of groups.
  3196. function Registry:RegisterDefaultCommands (arrayOrFunc)
  3197. local isArray = type(arrayOrFunc) == "table"
  3198.  
  3199. if isArray then
  3200. arrayOrFunc = Util.MakeDictionary(arrayOrFunc)
  3201. end
  3202.  
  3203. self:RegisterCommandsIn(self.Cmdr.DefaultCommandsFolder, isArray and function (command)
  3204. return arrayOrFunc[command.Group] or false
  3205. end or arrayOrFunc)
  3206. end
  3207.  
  3208. --- Gets a command definition by name. (Can be an alias)
  3209. function Registry:GetCommand (name)
  3210. name = name or ""
  3211. return self.Commands[name:lower()]
  3212. end
  3213.  
  3214. --- Returns a unique array of all registered commands (not including aliases)
  3215. function Registry:GetCommands ()
  3216. return self.CommandsArray
  3217. end
  3218.  
  3219. --- Returns an array of the names of all registered commands (not including aliases)
  3220. function Registry:GetCommandsAsStrings ()
  3221. local commands = {}
  3222.  
  3223. for _, command in pairs(self.CommandsArray) do
  3224. commands[#commands + 1] = command.Name
  3225. end
  3226.  
  3227. return commands
  3228. end
  3229.  
  3230. --- Gets a type definition by name.
  3231. function Registry:GetType (name)
  3232. return self.Types[name]
  3233. end
  3234.  
  3235. --- Adds a hook to be called when any command is run
  3236. function Registry:RegisterHook(hookName, callback, priority)
  3237. if not self.Hooks[hookName] then
  3238. error(("Invalid hook name: %q"):format(hookName), 2)
  3239. end
  3240.  
  3241. table.insert(self.Hooks[hookName], { callback = callback; priority = priority or 0; } )
  3242. table.sort(self.Hooks[hookName], function(a, b) return a.priority < b.priority end)
  3243. end
  3244.  
  3245. -- Backwards compatability (deprecated)
  3246. Registry.AddHook = Registry.RegisterHook
  3247.  
  3248. --- Returns the store with the given name
  3249. -- Used for commands that require persistent state, like bind or ban
  3250. function Registry:GetStore(name)
  3251. return self.Stores[name]
  3252. end
  3253.  
  3254. --- Calls self:FlushAutoExecBuffer at the end of the frame
  3255. function Registry:FlushAutoExecBufferDeferred()
  3256. if self.AutoExecFlushConnection then
  3257. return
  3258. end
  3259.  
  3260. self.AutoExecFlushConnection = RunService.Heartbeat:Connect(function()
  3261. self.AutoExecFlushConnection:Disconnect()
  3262. self.AutoExecFlushConnection = nil
  3263. self:FlushAutoExecBuffer()
  3264. end)
  3265. end
  3266.  
  3267. --- Runs all pending auto exec commands in Registry.AutoExecBuffer
  3268. function Registry:FlushAutoExecBuffer()
  3269. for _, commandGroup in ipairs(self.AutoExecBuffer) do
  3270. for _, command in ipairs(commandGroup) do
  3271. self.Cmdr.Dispatcher:EvaluateAndRun(command)
  3272. end
  3273. end
  3274. end
  3275.  
  3276. return function (cmdr)
  3277. Registry.Cmdr = cmdr
  3278.  
  3279. return Registry
  3280. end
  3281. ]]></ProtectedString>
  3282. <BinaryString name="Tags"></BinaryString>
  3283. </Properties>
  3284. </Item>
  3285. <Item class="ModuleScript" referent="RBXC7702180AA01435AA52F6BAFCD075B38">
  3286. <Properties>
  3287. <Content name="LinkedSource"><null></null></Content>
  3288. <string name="Name">Util</string>
  3289. <string name="ScriptGuid">{4CD0DF40-7153-4B7F-92BD-1697277A9BF8}</string>
  3290. <ProtectedString name="Source"><![CDATA[-- A fully extensible and type-safe admin-commands console
  3291. -- @documentation https://github.com/evaera/Cmdr/blob/master/README.md
  3292. -- @source https://github.com/evaera/Cmdr
  3293. -- @rostrap Cmdr
  3294. -- @author evaera
  3295.  
  3296. local TextService = game:GetService("TextService")
  3297.  
  3298. local Util = {}
  3299.  
  3300. --- Takes an array and flips its values into dictionary keys with value of true.
  3301. function Util.MakeDictionary(array)
  3302. local dictionary = {}
  3303.  
  3304. for i = 1, #array do
  3305. dictionary[array[i]] = true
  3306. end
  3307.  
  3308. return dictionary
  3309. end
  3310.  
  3311. -- Takes an array of instances and returns (array<names>, array<instances>)
  3312. local function transformInstanceSet(instances)
  3313. local names = {}
  3314.  
  3315. for i = 1, #instances do
  3316. names[i] = instances[i].Name
  3317. end
  3318.  
  3319. return names, instances
  3320. end
  3321.  
  3322. --- Returns a function that is a fuzzy finder for the specified set or container.
  3323. -- Can pass an array of strings, array of instances, array of EnumItems,
  3324. -- array of dictionaries with a Name key or an instance (in which case its children will be used)
  3325. -- Exact matches will be inserted in the front of the resulting array
  3326. function Util.MakeFuzzyFinder(setOrContainer)
  3327. local names
  3328. local instances = {}
  3329.  
  3330. if typeof(setOrContainer) == "Enum" then
  3331. setOrContainer = setOrContainer:GetEnumItems()
  3332. end
  3333.  
  3334. if typeof(setOrContainer) == "Instance" then
  3335. names, instances = transformInstanceSet(setOrContainer:GetChildren())
  3336. elseif typeof(setOrContainer) == "table" then
  3337. if
  3338. typeof(setOrContainer[1]) == "Instance" or typeof(setOrContainer[1]) == "EnumItem" or
  3339. (typeof(setOrContainer[1]) == "table" and typeof(setOrContainer[1].Name) == "string")
  3340. then
  3341. names, instances = transformInstanceSet(setOrContainer)
  3342. elseif type(setOrContainer[1]) == "string" then
  3343. names = setOrContainer
  3344. elseif setOrContainer[1] ~= nil then
  3345. error("MakeFuzzyFinder only accepts tables of instances or strings.")
  3346. else
  3347. names = {}
  3348. end
  3349. else
  3350. error("MakeFuzzyFinder only accepts a table, Enum, or Instance.")
  3351. end
  3352.  
  3353. -- Searches the set (checking exact matches first)
  3354. return function(text, returnFirst)
  3355. local results = {}
  3356.  
  3357. for i, name in pairs(names) do
  3358. local value = instances and instances[i] or name
  3359.  
  3360. -- Continue on checking for non-exact matches...
  3361. -- Still need to loop through everything, even on returnFirst, because possibility of an exact match.
  3362. if name:lower() == text:lower() then
  3363. if returnFirst then
  3364. return value
  3365. else
  3366. table.insert(results, 1, value)
  3367. end
  3368. elseif name:lower():sub(1, #text) == text:lower() then
  3369. results[#results + 1] = value
  3370. end
  3371. end
  3372.  
  3373. if returnFirst then
  3374. return results[1]
  3375. end
  3376.  
  3377. return results
  3378. end
  3379. end
  3380.  
  3381. --- Takes an array of instances and returns an array of those instances' names.
  3382. function Util.GetNames(instances)
  3383. local names = {}
  3384.  
  3385. for i = 1, #instances do
  3386. names[i] = instances[i].Name or tostring(instances[i])
  3387. end
  3388.  
  3389. return names
  3390. end
  3391.  
  3392. --- Splits a string using a simple separator (no quote parsing)
  3393. function Util.SplitStringSimple(inputstr, sep)
  3394. if sep == nil then
  3395. sep = "%s"
  3396. end
  3397. local t = {}
  3398. local i = 1
  3399. for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
  3400. t[i] = str
  3401. i = i + 1
  3402. end
  3403. return t
  3404. end
  3405.  
  3406. local function charCode(n)
  3407. return utf8.char(tonumber(n, 16))
  3408. end
  3409.  
  3410. -- Discard any excess return values
  3411. local function first(x)
  3412. return x
  3413. end
  3414.  
  3415. --- Parses escape sequences into their fully qualified characters
  3416. function Util.ParseEscapeSequences(text)
  3417. return text:gsub("\\(.)", {
  3418. t = "\t";
  3419. n = "\n";
  3420. })
  3421. :gsub("\\u(%x%x%x%x)", charCode)
  3422. :gsub("\\x(%x%x)", charCode)
  3423. end
  3424.  
  3425. local function encodeControlChars(text)
  3426. return first(
  3427. text
  3428. :gsub("\\\\", string.char(17))
  3429. :gsub("\\\"", string.char(18))
  3430. :gsub("\\'", string.char(19))
  3431. )
  3432. end
  3433.  
  3434. local function decodeControlChars(text)
  3435. return first(
  3436. text
  3437. :gsub(string.char(17), "\\")
  3438. :gsub(string.char(18), "\"")
  3439. :gsub(string.char(19), "'")
  3440. )
  3441. end
  3442.  
  3443. --- Splits a string by space but taking into account quoted sequences which will be treated as a single argument.
  3444. function Util.SplitString(text, max)
  3445. text = encodeControlChars(text)
  3446. max = max or math.huge
  3447. local t = {}
  3448. local spat, epat, buf, quoted = [=[^(['"])]=], [=[(['"])$]=]
  3449. for str in text:gmatch("%S+") do
  3450. str = Util.ParseEscapeSequences(str)
  3451. local squoted = str:match(spat)
  3452. local equoted = str:match(epat)
  3453. local escaped = str:match([=[(\*)['"]$]=])
  3454. if squoted and not quoted and not equoted then
  3455. buf, quoted = str, squoted
  3456. elseif buf and equoted == quoted and #escaped % 2 == 0 then
  3457. str, buf, quoted = buf .. " " .. str, nil, nil
  3458. elseif buf then
  3459. buf = buf .. " " .. str
  3460. end
  3461. if not buf then
  3462. t[#t + (#t > max and 0 or 1)] = decodeControlChars(str:gsub(spat, ""):gsub(epat, ""))
  3463. end
  3464. end
  3465.  
  3466. if buf then
  3467. t[#t + (#t > max and 0 or 1)] = decodeControlChars(buf)
  3468. end
  3469.  
  3470. return t
  3471. end
  3472.  
  3473. --- Takes an array of arguments and a max value.
  3474. -- Any indicies past the max value will be appended to the last valid argument.
  3475. function Util.MashExcessArguments(arguments, max)
  3476. local t = {}
  3477. for i = 1, #arguments do
  3478. if i > max then
  3479. t[max] = ("%s %s"):format(t[max] or "", arguments[i])
  3480. else
  3481. t[i] = arguments[i]
  3482. end
  3483. end
  3484. return t
  3485. end
  3486.  
  3487. --- Trims whitespace from both sides of a string.
  3488. function Util.TrimString(s)
  3489. return s:match "^%s*(.-)%s*$"
  3490. end
  3491.  
  3492. --- Returns the text bounds size based on given text, label (from which properties will be pulled), and optional Vector2 container size.
  3493. function Util.GetTextSize(text, label, size)
  3494. return TextService:GetTextSize(text, label.TextSize, label.Font, size or Vector2.new(label.AbsoluteSize.X, 0))
  3495. end
  3496.  
  3497. --- Makes an Enum type.
  3498. function Util.MakeEnumType(name, values)
  3499. local findValue = Util.MakeFuzzyFinder(values)
  3500. return {
  3501. Validate = function(text)
  3502. return findValue(text, true) ~= nil, ("Value %q is not a valid %s."):format(text, name)
  3503. end,
  3504. Autocomplete = function(text)
  3505. local list = findValue(text)
  3506. return type(list[1]) ~= "string" and Util.GetNames(list) or list
  3507. end,
  3508. Parse = function(text)
  3509. return findValue(text, true)
  3510. end
  3511. }
  3512. end
  3513.  
  3514. --- Parses a prefixed union type argument (such as %Team)
  3515. function Util.ParsePrefixedUnionType(typeValue, rawValue)
  3516. local split = Util.SplitStringSimple(typeValue)
  3517.  
  3518. -- Check prefixes in order from longest to shortest
  3519. local types = {}
  3520. for i = 1, #split, 2 do
  3521. types[#types + 1] = {
  3522. prefix = split[i - 1] or "",
  3523. type = split[i]
  3524. }
  3525. end
  3526.  
  3527. table.sort(
  3528. types,
  3529. function(a, b)
  3530. return #a.prefix > #b.prefix
  3531. end
  3532. )
  3533.  
  3534. for i = 1, #types do
  3535. local t = types[i]
  3536.  
  3537. if rawValue:sub(1, #t.prefix) == t.prefix then
  3538. return t.type, rawValue:sub(#t.prefix + 1), t.prefix
  3539. end
  3540. end
  3541. end
  3542.  
  3543. --- Creates a listable type from a singlular type
  3544. function Util.MakeListableType(type)
  3545. local listableType = {
  3546. Listable = true,
  3547. Transform = type.Transform,
  3548. Validate = type.Validate,
  3549. Autocomplete = type.Autocomplete,
  3550. Parse = function(...)
  3551. return {type.Parse(...)}
  3552. end
  3553. }
  3554.  
  3555. return listableType
  3556. end
  3557.  
  3558. local function encodeCommandEscape(text)
  3559. return first(text:gsub("\\%$", string.char(20)))
  3560. end
  3561.  
  3562. local function decodeCommandEscape(text)
  3563. return first(text:gsub(string.char(20), "$"))
  3564. end
  3565.  
  3566. --- Runs embedded commands and replaces them
  3567. function Util.RunEmbeddedCommands(dispatcher, str)
  3568. str = encodeCommandEscape(str)
  3569.  
  3570. local results = {}
  3571. -- We need to do this because you can't yield in the gsub function
  3572. for text in str:gmatch("$(%b{})") do
  3573. local doQuotes = true
  3574. local commandString = text:sub(2, #text-1)
  3575.  
  3576. if commandString:match("^{.+}$") then -- Allow double curly for literal replacement
  3577. doQuotes = false
  3578. commandString = commandString:sub(2, #commandString-1)
  3579. end
  3580.  
  3581. results[text] = dispatcher:EvaluateAndRun(commandString)
  3582.  
  3583. if doQuotes and results[text]:find("%s") then
  3584. results[text] = string.format("%q", results[text])
  3585. end
  3586. end
  3587.  
  3588. return decodeCommandEscape(str:gsub("$(%b{})", results))
  3589. end
  3590.  
  3591. --- Replaces arguments in the format $1, $2, $something with whatever the
  3592. -- given function returns for it.
  3593. function Util.SubstituteArgs(str, replace)
  3594. str = encodeCommandEscape(str)
  3595. -- Convert numerical keys to strings
  3596. if type(replace) == "table" then
  3597. for i = 1, #replace do
  3598. local k = tostring(i)
  3599. replace[k] = replace[i]
  3600.  
  3601. if replace[k]:find("%s") then
  3602. replace[k] = string.format("%q", replace[k])
  3603. end
  3604. end
  3605. end
  3606. return decodeCommandEscape(str:gsub("$(%w+)", replace))
  3607. end
  3608.  
  3609. --- Creates an alias command
  3610. function Util.MakeAliasCommand(name, commandString)
  3611. return {
  3612. Name = name,
  3613. Aliases = {},
  3614. Description = commandString,
  3615. Group = "UserAlias",
  3616. Args = {
  3617. {
  3618. Type = "string",
  3619. Name = "Argument 1",
  3620. Description = "",
  3621. Default = ""
  3622. },
  3623. {
  3624. Type = "string",
  3625. Name = "Argument 2",
  3626. Description = "",
  3627. Default = ""
  3628. },
  3629. {
  3630. Type = "string",
  3631. Name = "Argument 3",
  3632. Description = "",
  3633. Default = ""
  3634. },
  3635. {
  3636. Type = "string",
  3637. Name = "Argument 4",
  3638. Description = "",
  3639. Default = ""
  3640. },
  3641. {
  3642. Type = "string",
  3643. Name = "Argument 5",
  3644. Description = "",
  3645. Default = ""
  3646. }
  3647. },
  3648. Run = function(context, ...)
  3649. local args = {...}
  3650. local commands = Util.SplitStringSimple(commandString, "&&")
  3651.  
  3652. for i, command in ipairs(commands) do
  3653. local output = context.Dispatcher:EvaluateAndRun(
  3654. Util.RunEmbeddedCommands(
  3655. context.Dispatcher,
  3656. Util.SubstituteArgs(command, args)
  3657. )
  3658. )
  3659. if i == #commands then
  3660. return output -- return last command's output
  3661. else
  3662. context:Reply(output)
  3663. end
  3664. end
  3665.  
  3666. return ""
  3667. end
  3668. }
  3669. end
  3670.  
  3671. --- Makes a type that contains a sequence, e.g. Vector3 or Color3
  3672. function Util.MakeSequenceType(options)
  3673. options = options or {}
  3674.  
  3675. assert(options.Parse ~= nil or options.Constructor ~= nil, "MakeSequenceType: Must provide one of: Constructor, Parse")
  3676.  
  3677. options.TransformEach = options.TransformEach or function(...)
  3678. return ...
  3679. end
  3680.  
  3681. options.ValidateEach = options.ValidateEach or function()
  3682. return true
  3683. end
  3684.  
  3685. return {
  3686. Transform = function (text)
  3687. return Util.Map(Util.SplitPrioritizedDelimeter(text, {",", "%s"}), function(value)
  3688. return options.TransformEach(value)
  3689. end)
  3690. end;
  3691.  
  3692. Validate = function (components)
  3693. if options.Length and #components > options.Length then
  3694. return false, ("Maximum of %d values allowed in sequence"):format(options.Length)
  3695. end
  3696.  
  3697. for i = 1, options.Length or #components do
  3698. local valid, reason = options.ValidateEach(components[i], i)
  3699.  
  3700. if not valid then
  3701. return false, reason
  3702. end
  3703. end
  3704.  
  3705. return true
  3706. end;
  3707.  
  3708. Parse = options.Parse or function(components)
  3709. return options.Constructor(unpack(components))
  3710. end
  3711. }
  3712. end
  3713.  
  3714. --- Splits a string by a single delimeter chosen from the given set.
  3715. -- The first matching delimeter from the set becomes the split character.
  3716. function Util.SplitPrioritizedDelimeter(text, delimeters)
  3717. for i, delimeter in ipairs(delimeters) do
  3718. if text:find(delimeter) or i == #delimeters then
  3719. return Util.SplitStringSimple(text, delimeter)
  3720. end
  3721. end
  3722. end
  3723.  
  3724. --- Maps values of an array through a callback and returns an array of mapped values
  3725. function Util.Map(array, callback)
  3726. local results = {}
  3727.  
  3728. for i, v in ipairs(array) do
  3729. results[i] = callback(v, i)
  3730. end
  3731.  
  3732. return results
  3733. end
  3734.  
  3735. --- Maps arguments #2-n through callback and returns values as tuple
  3736. function Util.Each(callback, ...)
  3737. local results = {}
  3738. for i, value in ipairs({...}) do
  3739. results[i] = callback(value)
  3740. end
  3741. return unpack(results)
  3742. end
  3743.  
  3744. --- Emulates tabstops with spaces
  3745. function Util.EmulateTabstops(text, tabWidth)
  3746. local result = ""
  3747. for i = 1, #text do
  3748. local char = text:sub(i, i)
  3749.  
  3750. result = result .. (char == "\t" and string.rep(" ", tabWidth - #result % tabWidth) or char)
  3751. end
  3752. return result
  3753. end
  3754.  
  3755. return Util
  3756. ]]></ProtectedString>
  3757. <BinaryString name="Tags"></BinaryString>
  3758. </Properties>
  3759. </Item>
  3760. </Item>
  3761. <Item class="ModuleScript" referent="RBX896F91C3C40E46B4A1781B9D98F5FB1E">
  3762. <Properties>
  3763. <Content name="LinkedSource"><null></null></Content>
  3764. <string name="Name">Loadstring</string>
  3765. <string name="ScriptGuid">{162F5D71-14B8-4FFC-AEDD-E8D0D282AD31}</string>
  3766. <ProtectedString name="Source"><![CDATA[--[[
  3767. Credit to einsteinK.
  3768. Credit to Stravant for LBI.
  3769.  
  3770. Credit to the creators of all the other modules used in this.
  3771.  
  3772. Sceleratis was here and decided modify some things.
  3773.  
  3774. einsteinK was here again to fix a bug in LBI for if-statements
  3775. --]]
  3776.  
  3777. local waitDeps = {
  3778. 'Rerubi';
  3779. 'LuaK';
  3780. 'LuaP';
  3781. 'LuaU';
  3782. 'LuaX';
  3783. 'LuaY';
  3784. 'LuaZ';
  3785. }
  3786.  
  3787. for i,v in pairs(waitDeps) do script:WaitForChild(v) end
  3788.  
  3789. local luaX = require(script.LuaX)
  3790. local luaY = require(script.LuaY)
  3791. local luaZ = require(script.LuaZ)
  3792. local luaU = require(script.LuaU)
  3793. local rerubi = require(script.Rerubi)
  3794.  
  3795. luaX:init()
  3796. local LuaState = {}
  3797.  
  3798. getfenv().script = nil
  3799.  
  3800. return function(str,env)
  3801. local f,writer,buff,name
  3802. local env = env or getfenv(2)
  3803. local name = (env.script and env.script:GetFullName())
  3804. local ran,error = pcall(function()
  3805. local zio = luaZ:init(luaZ:make_getS(str), nil)
  3806. if not zio then return error() end
  3807. local func = luaY:parser(LuaState, zio, nil, name or "nil")
  3808. writer, buff = luaU:make_setS()
  3809. luaU:dump(LuaState, func, writer, buff)
  3810. f = rerubi(buff.data, env)
  3811. end)
  3812.  
  3813. if ran then
  3814. return f,buff.data
  3815. else
  3816. return nil,error
  3817. end
  3818. end]]></ProtectedString>
  3819. <BinaryString name="Tags"></BinaryString>
  3820. </Properties>
  3821. <Item class="ModuleScript" referent="RBX139BCE3209D84EE097021EF03E3CD256">
  3822. <Properties>
  3823. <Content name="LinkedSource"><null></null></Content>
  3824. <string name="Name">LuaZ</string>
  3825. <string name="ScriptGuid">{6A425F9D-9F7A-417C-A445-E264422EEBDE}</string>
  3826. <ProtectedString name="Source"><![CDATA[--[[--------------------------------------------------------------------
  3827.  
  3828. lzio.lua
  3829. Lua buffered streams in Lua
  3830. This file is part of Yueliang.
  3831.  
  3832. Copyright (c) 2005-2006 Kein-Hong Man <[email protected]>
  3833. The COPYRIGHT file describes the conditions
  3834. under which this software may be distributed.
  3835.  
  3836. See the ChangeLog for more information.
  3837.  
  3838. ----------------------------------------------------------------------]]
  3839.  
  3840. --[[--------------------------------------------------------------------
  3841. -- Notes:
  3842. -- * EOZ is implemented as a string, "EOZ"
  3843. -- * Format of z structure (ZIO)
  3844. -- z.n -- bytes still unread
  3845. -- z.p -- last read position position in buffer
  3846. -- z.reader -- chunk reader function
  3847. -- z.data -- additional data
  3848. -- * Current position, p, is now last read index instead of a pointer
  3849. --
  3850. -- Not implemented:
  3851. -- * luaZ_lookahead: used only in lapi.c:lua_load to detect binary chunk
  3852. -- * luaZ_read: used only in lundump.c:ezread to read +1 bytes
  3853. -- * luaZ_openspace: dropped; let Lua handle buffers as strings (used in
  3854. -- lundump.c:LoadString & lvm.c:luaV_concat)
  3855. -- * luaZ buffer macros: dropped; buffers are handled as strings
  3856. -- * lauxlib.c:getF reader implementation has an extraline flag to
  3857. -- skip over a shbang (#!) line, this is not implemented here
  3858. --
  3859. -- Added:
  3860. -- (both of the following are vaguely adapted from lauxlib.c)
  3861. -- * luaZ:make_getS: create Reader from a string
  3862. -- * luaZ:make_getF: create Reader that reads from a file
  3863. --
  3864. -- Changed in 5.1.x:
  3865. -- * Chunkreader renamed to Reader (ditto with Chunkwriter)
  3866. -- * Zio struct: no more name string, added Lua state for reader
  3867. -- (however, Yueliang readers do not require a Lua state)
  3868. ----------------------------------------------------------------------]]
  3869.  
  3870. local luaZ = {}
  3871.  
  3872. ------------------------------------------------------------------------
  3873. -- * reader() should return a string, or nil if nothing else to parse.
  3874. -- Additional data can be set only during stream initialization
  3875. -- * Readers are handled in lauxlib.c, see luaL_load(file|buffer|string)
  3876. -- * LUAL_BUFFERSIZE=BUFSIZ=512 in make_getF() (located in luaconf.h)
  3877. -- * Original Reader typedef:
  3878. -- const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
  3879. -- * This Lua chunk reader implementation:
  3880. -- returns string or nil, no arguments to function
  3881. ------------------------------------------------------------------------
  3882.  
  3883. ------------------------------------------------------------------------
  3884. -- create a chunk reader from a source string
  3885. ------------------------------------------------------------------------
  3886. function luaZ:make_getS(buff)
  3887. local b = buff
  3888. return function() -- chunk reader anonymous function here
  3889. if not b then return nil end
  3890. local data = b
  3891. b = nil
  3892. return data
  3893. end
  3894. end
  3895.  
  3896. ------------------------------------------------------------------------
  3897. -- create a chunk reader from a source file
  3898. ------------------------------------------------------------------------
  3899. --[[
  3900. function luaZ:make_getF(filename)
  3901. local LUAL_BUFFERSIZE = 512
  3902. local h = io.open(filename, "r")
  3903. if not h then return nil end
  3904. return function() -- chunk reader anonymous function here
  3905. if not h or io.type(h) == "closed file" then return nil end
  3906. local buff = h:read(LUAL_BUFFERSIZE)
  3907. if not buff then h:close(); h = nil end
  3908. return buff
  3909. end
  3910. end
  3911. --]]
  3912. ------------------------------------------------------------------------
  3913. -- creates a zio input stream
  3914. -- returns the ZIO structure, z
  3915. ------------------------------------------------------------------------
  3916. function luaZ:init(reader, data, name)
  3917. if not reader then return end
  3918. local z = {}
  3919. z.reader = reader
  3920. z.data = data or ""
  3921. z.name = name
  3922. -- set up additional data for reading
  3923. if not data or data == "" then z.n = 0 else z.n = #data end
  3924. z.p = 0
  3925. return z
  3926. end
  3927.  
  3928. ------------------------------------------------------------------------
  3929. -- fill up input buffer
  3930. ------------------------------------------------------------------------
  3931. function luaZ:fill(z)
  3932. local buff = z.reader()
  3933. z.data = buff
  3934. if not buff or buff == "" then return "EOZ" end
  3935. z.n, z.p = #buff - 1, 1
  3936. return string.sub(buff, 1, 1)
  3937. end
  3938.  
  3939. ------------------------------------------------------------------------
  3940. -- get next character from the input stream
  3941. -- * local n, p are used to optimize code generation
  3942. ------------------------------------------------------------------------
  3943. function luaZ:zgetc(z)
  3944. local n, p = z.n, z.p + 1
  3945. if n > 0 then
  3946. z.n, z.p = n - 1, p
  3947. return string.sub(z.data, p, p)
  3948. else
  3949. return self:fill(z)
  3950. end
  3951. end
  3952.  
  3953. return luaZ]]></ProtectedString>
  3954. <BinaryString name="Tags"></BinaryString>
  3955. </Properties>
  3956. </Item>
  3957. <Item class="ModuleScript" referent="RBX74ED26F683644E6283E6F69B9920D64A">
  3958. <Properties>
  3959. <Content name="LinkedSource"><null></null></Content>
  3960. <string name="Name">LuaX</string>
  3961. <string name="ScriptGuid">{9514EDB3-FB50-4B26-B929-88952220C9D9}</string>
  3962. <ProtectedString name="Source"><![CDATA[--[[--------------------------------------------------------------------
  3963.  
  3964. llex.lua
  3965. Lua lexical analyzer in Lua
  3966. This file is part of Yueliang.
  3967.  
  3968. Copyright (c) 2005-2006 Kein-Hong Man <[email protected]>
  3969. The COPYRIGHT file describes the conditions
  3970. under which this software may be distributed.
  3971.  
  3972. See the ChangeLog for more information.
  3973.  
  3974. ----------------------------------------------------------------------]]
  3975.  
  3976. --[[--------------------------------------------------------------------
  3977. -- Notes:
  3978. -- * intended to 'imitate' llex.c code; performance is not a concern
  3979. -- * tokens are strings; code structure largely retained
  3980. -- * deleted stuff (compared to llex.c) are noted, comments retained
  3981. -- * nextc() returns the currently read character to simplify coding
  3982. -- here; next() in llex.c does not return anything
  3983. -- * compatibility code is marked with "--#" comments
  3984. --
  3985. -- Added:
  3986. -- * luaX:chunkid (function luaO_chunkid from lobject.c)
  3987. -- * luaX:str2d (function luaO_str2d from lobject.c)
  3988. -- * luaX.LUA_QS used in luaX:lexerror (from luaconf.h)
  3989. -- * luaX.LUA_COMPAT_LSTR in luaX:read_long_string (from luaconf.h)
  3990. -- * luaX.MAX_INT used in luaX:inclinenumber (from llimits.h)
  3991. --
  3992. -- To use the lexer:
  3993. -- (1) luaX:init() to initialize the lexer
  3994. -- (2) luaX:setinput() to set the input stream to lex
  3995. -- (3) call luaX:next() or luaX:luaX:lookahead() to get tokens,
  3996. -- until "TK_EOS": luaX:next()
  3997. -- * since EOZ is returned as a string, be careful when regexp testing
  3998. --
  3999. -- Not implemented:
  4000. -- * luaX_newstring: not required by this Lua implementation
  4001. -- * buffer MAX_SIZET size limit (from llimits.h) test not implemented
  4002. -- in the interest of performance
  4003. -- * locale-aware number handling is largely redundant as Lua's
  4004. -- tonumber() function is already capable of this
  4005. --
  4006. -- Changed in 5.1.x:
  4007. -- * TK_NAME token order moved down
  4008. -- * string representation for TK_NAME, TK_NUMBER, TK_STRING changed
  4009. -- * token struct renamed to lower case (LS -> ls)
  4010. -- * LexState struct: removed nestlevel, added decpoint
  4011. -- * error message functions have been greatly simplified
  4012. -- * token2string renamed to luaX_tokens, exposed in llex.h
  4013. -- * lexer now handles all kinds of newlines, including CRLF
  4014. -- * shbang first line handling removed from luaX:setinput;
  4015. -- it is now done in lauxlib.c (luaL_loadfile)
  4016. -- * next(ls) macro renamed to nextc(ls) due to new luaX_next function
  4017. -- * EXTRABUFF and MAXNOCHECK removed due to lexer changes
  4018. -- * checkbuffer(ls, len) macro deleted
  4019. -- * luaX:read_numeral now has 3 support functions: luaX:trydecpoint,
  4020. -- luaX:buffreplace and (luaO_str2d from lobject.c) luaX:str2d
  4021. -- * luaX:read_numeral is now more promiscuous in slurping characters;
  4022. -- hexadecimal numbers was added, locale-aware decimal points too
  4023. -- * luaX:skip_sep is new; used by luaX:read_long_string
  4024. -- * luaX:read_long_string handles new-style long blocks, with some
  4025. -- optional compatibility code
  4026. -- * luaX:llex: parts changed to support new-style long blocks
  4027. -- * luaX:llex: readname functionality has been folded in
  4028. -- * luaX:llex: removed test for control characters
  4029. --
  4030. --------------------------------------------------------------------]]
  4031.  
  4032. local luaZ = require(script.Parent.LuaZ)
  4033.  
  4034. local luaX = {}
  4035.  
  4036. -- FIRST_RESERVED is not required as tokens are manipulated as strings
  4037. -- TOKEN_LEN deleted; maximum length of a reserved word not needed
  4038.  
  4039. ------------------------------------------------------------------------
  4040. -- "ORDER RESERVED" deleted; enumeration in one place: luaX.RESERVED
  4041. ------------------------------------------------------------------------
  4042.  
  4043. -- terminal symbols denoted by reserved words: TK_AND to TK_WHILE
  4044. -- other terminal symbols: TK_NAME to TK_EOS
  4045. luaX.RESERVED = [[
  4046. TK_AND and
  4047. TK_BREAK break
  4048. TK_DO do
  4049. TK_ELSE else
  4050. TK_ELSEIF elseif
  4051. TK_END end
  4052. TK_FALSE false
  4053. TK_FOR for
  4054. TK_FUNCTION function
  4055. TK_IF if
  4056. TK_IN in
  4057. TK_LOCAL local
  4058. TK_NIL nil
  4059. TK_NOT not
  4060. TK_OR or
  4061. TK_REPEAT repeat
  4062. TK_RETURN return
  4063. TK_THEN then
  4064. TK_TRUE true
  4065. TK_UNTIL until
  4066. TK_WHILE while
  4067. TK_CONCAT ..
  4068. TK_DOTS ...
  4069. TK_EQ ==
  4070. TK_GE >=
  4071. TK_LE <=
  4072. TK_NE ~=
  4073. TK_NAME <name>
  4074. TK_NUMBER <number>
  4075. TK_STRING <string>
  4076. TK_EOS <eof>]]
  4077.  
  4078. -- NUM_RESERVED is not required; number of reserved words
  4079.  
  4080. --[[--------------------------------------------------------------------
  4081. -- Instead of passing seminfo, the Token struct (e.g. ls.t) is passed
  4082. -- so that lexer functions can use its table element, ls.t.seminfo
  4083. --
  4084. -- SemInfo (struct no longer needed, a mixed-type value is used)
  4085. --
  4086. -- Token (struct of ls.t and ls.lookahead):
  4087. -- token -- token symbol
  4088. -- seminfo -- semantics information
  4089. --
  4090. -- LexState (struct of ls; ls is initialized by luaX:setinput):
  4091. -- current -- current character (charint)
  4092. -- linenumber -- input line counter
  4093. -- lastline -- line of last token 'consumed'
  4094. -- t -- current token (table: struct Token)
  4095. -- lookahead -- look ahead token (table: struct Token)
  4096. -- fs -- 'FuncState' is private to the parser
  4097. -- L -- LuaState
  4098. -- z -- input stream
  4099. -- buff -- buffer for tokens
  4100. -- source -- current source name
  4101. -- decpoint -- locale decimal point
  4102. -- nestlevel -- level of nested non-terminals
  4103. ----------------------------------------------------------------------]]
  4104.  
  4105. -- luaX.tokens (was luaX_tokens) is now a hash; see luaX:init
  4106.  
  4107. luaX.MAXSRC = 80
  4108. luaX.MAX_INT = 2147483645 -- constants from elsewhere (see above)
  4109. luaX.LUA_QS = "'%s'"
  4110. luaX.LUA_COMPAT_LSTR = 1
  4111. --luaX.MAX_SIZET = 4294967293
  4112.  
  4113. ------------------------------------------------------------------------
  4114. -- initialize lexer
  4115. -- * original luaX_init has code to create and register token strings
  4116. -- * luaX.tokens: TK_* -> token
  4117. -- * luaX.enums: token -> TK_* (used in luaX:llex)
  4118. ------------------------------------------------------------------------
  4119. function luaX:init()
  4120. local tokens, enums = {}, {}
  4121. for v in string.gmatch(self.RESERVED, "[^\n]+") do
  4122. local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)")
  4123. tokens[tok] = str
  4124. enums[str] = tok
  4125. end
  4126. self.tokens = tokens
  4127. self.enums = enums
  4128. end
  4129.  
  4130. ------------------------------------------------------------------------
  4131. -- returns a suitably-formatted chunk name or id
  4132. -- * from lobject.c, used in llex.c and ldebug.c
  4133. -- * the result, out, is returned (was first argument)
  4134. ------------------------------------------------------------------------
  4135. function luaX:chunkid(source, bufflen)
  4136. local out
  4137. local first = string.sub(source, 1, 1)
  4138. if first == "=" then
  4139. out = string.sub(source, 2, bufflen) -- remove first char
  4140. else -- out = "source", or "...source"
  4141. if first == "@" then
  4142. source = string.sub(source, 2) -- skip the '@'
  4143. bufflen = bufflen - #" '...' "
  4144. local l = #source
  4145. out = ""
  4146. if l > bufflen then
  4147. source = string.sub(source, 1 + l - bufflen) -- get last part of file name
  4148. out = out.."..."
  4149. end
  4150. out = out..source
  4151. else -- out = [string "string"]
  4152. local len = string.find(source, "[\n\r]") -- stop at first newline
  4153. len = len and (len - 1) or #source
  4154. bufflen = bufflen - #(" [string \"...\"] ")
  4155. if len > bufflen then len = bufflen end
  4156. out = "[string \""
  4157. if len < #source then -- must truncate?
  4158. out = out..string.sub(source, 1, len).."..."
  4159. else
  4160. out = out..source
  4161. end
  4162. out = out.."\"]"
  4163. end
  4164. end
  4165. return out
  4166. end
  4167.  
  4168. --[[--------------------------------------------------------------------
  4169. -- Support functions for lexer
  4170. -- * all lexer errors eventually reaches lexerror:
  4171. syntaxerror -> lexerror
  4172. ----------------------------------------------------------------------]]
  4173.  
  4174. ------------------------------------------------------------------------
  4175. -- look up token and return keyword if found (also called by parser)
  4176. ------------------------------------------------------------------------
  4177. function luaX:token2str(ls, token)
  4178. if string.sub(token, 1, 3) ~= "TK_" then
  4179. if string.find(token, "%c") then
  4180. return string.format("char(%d)", string.byte(token))
  4181. end
  4182. return token
  4183. else
  4184. end
  4185. return self.tokens[token]
  4186. end
  4187.  
  4188. ------------------------------------------------------------------------
  4189. -- throws a lexer error
  4190. -- * txtToken has been made local to luaX:lexerror
  4191. -- * can't communicate LUA_ERRSYNTAX, so it is unimplemented
  4192. ------------------------------------------------------------------------
  4193. function luaX:lexerror(ls, msg, token)
  4194. local function txtToken(ls, token)
  4195. if token == "TK_NAME" or
  4196. token == "TK_STRING" or
  4197. token == "TK_NUMBER" then
  4198. return ls.buff
  4199. else
  4200. return self:token2str(ls, token)
  4201. end
  4202. end
  4203. local buff = self:chunkid(ls.source, self.MAXSRC)
  4204. local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg)
  4205. if token then
  4206. msg = string.format("%s near "..self.LUA_QS, msg, txtToken(ls, token))
  4207. end
  4208. -- luaD_throw(ls->L, LUA_ERRSYNTAX)
  4209. error(msg)
  4210. end
  4211.  
  4212. ------------------------------------------------------------------------
  4213. -- throws a syntax error (mainly called by parser)
  4214. -- * ls.t.token has to be set by the function calling luaX:llex
  4215. -- (see luaX:next and luaX:lookahead elsewhere in this file)
  4216. ------------------------------------------------------------------------
  4217. function luaX:syntaxerror(ls, msg)
  4218. self:lexerror(ls, msg, ls.t.token)
  4219. end
  4220.  
  4221. ------------------------------------------------------------------------
  4222. -- move on to next line
  4223. ------------------------------------------------------------------------
  4224. function luaX:currIsNewline(ls)
  4225. return ls.current == "\n" or ls.current == "\r"
  4226. end
  4227.  
  4228. function luaX:inclinenumber(ls)
  4229. local old = ls.current
  4230. -- lua_assert(currIsNewline(ls))
  4231. self:nextc(ls) -- skip '\n' or '\r'
  4232. if self:currIsNewline(ls) and ls.current ~= old then
  4233. self:nextc(ls) -- skip '\n\r' or '\r\n'
  4234. end
  4235. ls.linenumber = ls.linenumber + 1
  4236. if ls.linenumber >= self.MAX_INT then
  4237. self:syntaxerror(ls, "chunk has too many lines")
  4238. end
  4239. end
  4240.  
  4241. ------------------------------------------------------------------------
  4242. -- initializes an input stream for lexing
  4243. -- * if ls (the lexer state) is passed as a table, then it is filled in,
  4244. -- otherwise it has to be retrieved as a return value
  4245. -- * LUA_MINBUFFER not used; buffer handling not required any more
  4246. ------------------------------------------------------------------------
  4247. function luaX:setinput(L, ls, z, source)
  4248. if not ls then ls = {} end -- create struct
  4249. if not ls.lookahead then ls.lookahead = {} end
  4250. if not ls.t then ls.t = {} end
  4251. ls.decpoint = "."
  4252. ls.L = L
  4253. ls.lookahead.token = "TK_EOS" -- no look-ahead token
  4254. ls.z = z
  4255. ls.fs = nil
  4256. ls.linenumber = 1
  4257. ls.lastline = 1
  4258. ls.source = source
  4259. self:nextc(ls) -- read first char
  4260. end
  4261.  
  4262. --[[--------------------------------------------------------------------
  4263. -- LEXICAL ANALYZER
  4264. ----------------------------------------------------------------------]]
  4265.  
  4266. ------------------------------------------------------------------------
  4267. -- checks if current character read is found in the set 'set'
  4268. ------------------------------------------------------------------------
  4269. function luaX:check_next(ls, set)
  4270. if not string.find(set, ls.current, 1, 1) then
  4271. return false
  4272. end
  4273. self:save_and_next(ls)
  4274. return true
  4275. end
  4276.  
  4277. ------------------------------------------------------------------------
  4278. -- retrieve next token, checking the lookahead buffer if necessary
  4279. -- * note that the macro next(ls) in llex.c is now luaX:nextc
  4280. -- * utilized used in lparser.c (various places)
  4281. ------------------------------------------------------------------------
  4282. function luaX:next(ls)
  4283. ls.lastline = ls.linenumber
  4284. if ls.lookahead.token ~= "TK_EOS" then -- is there a look-ahead token?
  4285. -- this must be copy-by-value
  4286. ls.t.seminfo = ls.lookahead.seminfo -- use this one
  4287. ls.t.token = ls.lookahead.token
  4288. ls.lookahead.token = "TK_EOS" -- and discharge it
  4289. else
  4290. ls.t.token = self:llex(ls, ls.t) -- read next token
  4291. end
  4292. end
  4293.  
  4294. ------------------------------------------------------------------------
  4295. -- fill in the lookahead buffer
  4296. -- * utilized used in lparser.c:constructor
  4297. ------------------------------------------------------------------------
  4298. function luaX:lookahead(ls)
  4299. -- lua_assert(ls.lookahead.token == "TK_EOS")
  4300. ls.lookahead.token = self:llex(ls, ls.lookahead)
  4301. end
  4302.  
  4303. ------------------------------------------------------------------------
  4304. -- gets the next character and returns it
  4305. -- * this is the next() macro in llex.c; see notes at the beginning
  4306. ------------------------------------------------------------------------
  4307. function luaX:nextc(ls)
  4308. local c = luaZ:zgetc(ls.z)
  4309. ls.current = c
  4310. return c
  4311. end
  4312.  
  4313. ------------------------------------------------------------------------
  4314. -- saves the given character into the token buffer
  4315. -- * buffer handling code removed, not used in this implementation
  4316. -- * test for maximum token buffer length not used, makes things faster
  4317. ------------------------------------------------------------------------
  4318.  
  4319. function luaX:save(ls, c)
  4320. local buff = ls.buff
  4321. -- if you want to use this, please uncomment luaX.MAX_SIZET further up
  4322. --if #buff > self.MAX_SIZET then
  4323. -- self:lexerror(ls, "lexical element too long")
  4324. --end
  4325. ls.buff = buff..c
  4326. end
  4327.  
  4328. ------------------------------------------------------------------------
  4329. -- save current character into token buffer, grabs next character
  4330. -- * like luaX:nextc, returns the character read for convenience
  4331. ------------------------------------------------------------------------
  4332. function luaX:save_and_next(ls)
  4333. self:save(ls, ls.current)
  4334. return self:nextc(ls)
  4335. end
  4336.  
  4337. ------------------------------------------------------------------------
  4338. -- LUA_NUMBER
  4339. -- * luaX:read_numeral is the main lexer function to read a number
  4340. -- * luaX:str2d, luaX:buffreplace, luaX:trydecpoint are support functions
  4341. ------------------------------------------------------------------------
  4342.  
  4343. ------------------------------------------------------------------------
  4344. -- string to number converter (was luaO_str2d from lobject.c)
  4345. -- * returns the number, nil if fails (originally returns a boolean)
  4346. -- * conversion function originally lua_str2number(s,p), a macro which
  4347. -- maps to the strtod() function by default (from luaconf.h)
  4348. ------------------------------------------------------------------------
  4349. function luaX:str2d(s)
  4350. local result = tonumber(s)
  4351. if result then return result end
  4352. -- conversion failed
  4353. if string.lower(string.sub(s, 1, 2)) == "0x" then -- maybe an hexadecimal constant?
  4354. result = tonumber(s, 16)
  4355. if result then return result end -- most common case
  4356. -- Was: invalid trailing characters?
  4357. -- In C, this function then skips over trailing spaces.
  4358. -- true is returned if nothing else is found except for spaces.
  4359. -- If there is still something else, then it returns a false.
  4360. -- All this is not necessary using Lua's tonumber.
  4361. end
  4362. return nil
  4363. end
  4364.  
  4365. ------------------------------------------------------------------------
  4366. -- single-character replacement, for locale-aware decimal points
  4367. ------------------------------------------------------------------------
  4368. function luaX:buffreplace(ls, from, to)
  4369. local result, buff = "", ls.buff
  4370. for p = 1, #buff do
  4371. local c = string.sub(buff, p, p)
  4372. if c == from then c = to end
  4373. result = result..c
  4374. end
  4375. ls.buff = result
  4376. end
  4377.  
  4378. ------------------------------------------------------------------------
  4379. -- Attempt to convert a number by translating '.' decimal points to
  4380. -- the decimal point character used by the current locale. This is not
  4381. -- needed in Yueliang as Lua's tonumber() is already locale-aware.
  4382. -- Instead, the code is here in case the user implements localeconv().
  4383. ------------------------------------------------------------------------
  4384. function luaX:trydecpoint(ls, Token)
  4385. -- format error: try to update decimal point separator
  4386. local old = ls.decpoint
  4387. -- translate the following to Lua if you implement localeconv():
  4388. -- struct lconv *cv = localeconv();
  4389. -- ls->decpoint = (cv ? cv->decimal_point[0] : '.');
  4390. self:buffreplace(ls, old, ls.decpoint) -- try updated decimal separator
  4391. local seminfo = self:str2d(ls.buff)
  4392. Token.seminfo = seminfo
  4393. if not seminfo then
  4394. -- format error with correct decimal point: no more options
  4395. self:buffreplace(ls, ls.decpoint, ".") -- undo change (for error message)
  4396. self:lexerror(ls, "malformed number", "TK_NUMBER")
  4397. end
  4398. end
  4399.  
  4400. ------------------------------------------------------------------------
  4401. -- main number conversion function
  4402. -- * "^%w$" needed in the scan in order to detect "EOZ"
  4403. ------------------------------------------------------------------------
  4404. function luaX:read_numeral(ls, Token)
  4405. -- lua_assert(string.find(ls.current, "%d"))
  4406. repeat
  4407. self:save_and_next(ls)
  4408. until string.find(ls.current, "%D") and ls.current ~= "."
  4409. if self:check_next(ls, "Ee") then -- 'E'?
  4410. self:check_next(ls, "+-") -- optional exponent sign
  4411. end
  4412. while string.find(ls.current, "^%w$") or ls.current == "_" do
  4413. self:save_and_next(ls)
  4414. end
  4415. self:buffreplace(ls, ".", ls.decpoint) -- follow locale for decimal point
  4416. local seminfo = self:str2d(ls.buff)
  4417. Token.seminfo = seminfo
  4418. if not seminfo then -- format error?
  4419. self:trydecpoint(ls, Token) -- try to update decimal point separator
  4420. end
  4421. end
  4422.  
  4423. ------------------------------------------------------------------------
  4424. -- count separators ("=") in a long string delimiter
  4425. -- * used by luaX:read_long_string
  4426. ------------------------------------------------------------------------
  4427. function luaX:skip_sep(ls)
  4428. local count = 0
  4429. local s = ls.current
  4430. -- lua_assert(s == "[" or s == "]")
  4431. self:save_and_next(ls)
  4432. while ls.current == "=" do
  4433. self:save_and_next(ls)
  4434. count = count + 1
  4435. end
  4436. return (ls.current == s) and count or (-count) - 1
  4437. end
  4438.  
  4439. ------------------------------------------------------------------------
  4440. -- reads a long string or long comment
  4441. ------------------------------------------------------------------------
  4442. function luaX:read_long_string(ls, Token, sep)
  4443. local cont = 0
  4444. self:save_and_next(ls) -- skip 2nd '['
  4445. if self:currIsNewline(ls) then -- string starts with a newline?
  4446. self:inclinenumber(ls) -- skip it
  4447. end
  4448. while true do
  4449. local c = ls.current
  4450. if c == "EOZ" then
  4451. self:lexerror(ls, Token and "unfinished long string" or
  4452. "unfinished long comment", "TK_EOS")
  4453. elseif c == "[" then
  4454. --# compatibility code start
  4455. if self.LUA_COMPAT_LSTR then
  4456. if self:skip_sep(ls) == sep then
  4457. self:save_and_next(ls) -- skip 2nd '['
  4458. cont = cont + 1
  4459. --# compatibility code start
  4460. if self.LUA_COMPAT_LSTR == 1 then
  4461. if sep == 0 then
  4462. self:lexerror(ls, "nesting of [[...]] is deprecated", "[")
  4463. end
  4464. end
  4465. --# compatibility code end
  4466. end
  4467. end
  4468. --# compatibility code end
  4469. elseif c == "]" then
  4470. if self:skip_sep(ls) == sep then
  4471. self:save_and_next(ls) -- skip 2nd ']'
  4472. --# compatibility code start
  4473. if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then
  4474. cont = cont - 1
  4475. if sep == 0 and cont >= 0 then break end
  4476. end
  4477. --# compatibility code end
  4478. break
  4479. end
  4480. elseif self:currIsNewline(ls) then
  4481. self:save(ls, "\n")
  4482. self:inclinenumber(ls)
  4483. if not Token then ls.buff = "" end -- avoid wasting space
  4484. else -- default
  4485. if Token then
  4486. self:save_and_next(ls)
  4487. else
  4488. self:nextc(ls)
  4489. end
  4490. end--if c
  4491. end--while
  4492. if Token then
  4493. local p = 3 + sep
  4494. Token.seminfo = string.sub(ls.buff, p, -p)
  4495. end
  4496. end
  4497.  
  4498. ------------------------------------------------------------------------
  4499. -- reads a string
  4500. -- * has been restructured significantly compared to the original C code
  4501. ------------------------------------------------------------------------
  4502.  
  4503. function luaX:read_string(ls, del, Token)
  4504. self:save_and_next(ls)
  4505. while ls.current ~= del do
  4506. local c = ls.current
  4507. if c == "EOZ" then
  4508. self:lexerror(ls, "unfinished string", "TK_EOS")
  4509. elseif self:currIsNewline(ls) then
  4510. self:lexerror(ls, "unfinished string", "TK_STRING")
  4511. elseif c == "\\" then
  4512. c = self:nextc(ls) -- do not save the '\'
  4513. if self:currIsNewline(ls) then -- go through
  4514. self:save(ls, "\n")
  4515. self:inclinenumber(ls)
  4516. elseif c ~= "EOZ" then -- will raise an error next loop
  4517. -- escapes handling greatly simplified here:
  4518. local i = string.find("abfnrtv", c, 1, 1)
  4519. if i then
  4520. self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i))
  4521. self:nextc(ls)
  4522. elseif not string.find(c, "%d") then
  4523. self:save_and_next(ls) -- handles \\, \", \', and \?
  4524. else -- \xxx
  4525. c, i = 0, 0
  4526. repeat
  4527. c = 10 * c + ls.current
  4528. self:nextc(ls)
  4529. i = i + 1
  4530. until i >= 3 or not string.find(ls.current, "%d")
  4531. if c > 255 then -- UCHAR_MAX
  4532. self:lexerror(ls, "escape sequence too large", "TK_STRING")
  4533. end
  4534. self:save(ls, string.char(c))
  4535. end
  4536. end
  4537. else
  4538. self:save_and_next(ls)
  4539. end--if c
  4540. end--while
  4541. self:save_and_next(ls) -- skip delimiter
  4542. Token.seminfo = string.sub(ls.buff, 2, -2)
  4543. end
  4544.  
  4545. ------------------------------------------------------------------------
  4546. -- main lexer function
  4547. ------------------------------------------------------------------------
  4548. function luaX:llex(ls, Token)
  4549. ls.buff = ""
  4550. while true do
  4551. local c = ls.current
  4552. ----------------------------------------------------------------
  4553. if self:currIsNewline(ls) then
  4554. self:inclinenumber(ls)
  4555. ----------------------------------------------------------------
  4556. elseif c == "-" then
  4557. c = self:nextc(ls)
  4558. if c ~= "-" then return "-" end
  4559. -- else is a comment
  4560. local sep = -1
  4561. if self:nextc(ls) == '[' then
  4562. sep = self:skip_sep(ls)
  4563. ls.buff = "" -- 'skip_sep' may dirty the buffer
  4564. end
  4565. if sep >= 0 then
  4566. self:read_long_string(ls, nil, sep) -- long comment
  4567. ls.buff = ""
  4568. else -- else short comment
  4569. while not self:currIsNewline(ls) and ls.current ~= "EOZ" do
  4570. self:nextc(ls)
  4571. end
  4572. end
  4573. ----------------------------------------------------------------
  4574. elseif c == "[" then
  4575. local sep = self:skip_sep(ls)
  4576. if sep >= 0 then
  4577. self:read_long_string(ls, Token, sep)
  4578. return "TK_STRING"
  4579. elseif sep == -1 then
  4580. return "["
  4581. else
  4582. self:lexerror(ls, "invalid long string delimiter", "TK_STRING")
  4583. end
  4584. ----------------------------------------------------------------
  4585. elseif c == "=" then
  4586. c = self:nextc(ls)
  4587. if c ~= "=" then return "="
  4588. else self:nextc(ls); return "TK_EQ" end
  4589. ----------------------------------------------------------------
  4590. elseif c == "<" then
  4591. c = self:nextc(ls)
  4592. if c ~= "=" then return "<"
  4593. else self:nextc(ls); return "TK_LE" end
  4594. ----------------------------------------------------------------
  4595. elseif c == ">" then
  4596. c = self:nextc(ls)
  4597. if c ~= "=" then return ">"
  4598. else self:nextc(ls); return "TK_GE" end
  4599. ----------------------------------------------------------------
  4600. elseif c == "~" then
  4601. c = self:nextc(ls)
  4602. if c ~= "=" then return "~"
  4603. else self:nextc(ls); return "TK_NE" end
  4604. ----------------------------------------------------------------
  4605. elseif c == "\"" or c == "'" then
  4606. self:read_string(ls, c, Token)
  4607. return "TK_STRING"
  4608. ----------------------------------------------------------------
  4609. elseif c == "." then
  4610. c = self:save_and_next(ls)
  4611. if self:check_next(ls, ".") then
  4612. if self:check_next(ls, ".") then
  4613. return "TK_DOTS" -- ...
  4614. else return "TK_CONCAT" -- ..
  4615. end
  4616. elseif not string.find(c, "%d") then
  4617. return "."
  4618. else
  4619. self:read_numeral(ls, Token)
  4620. return "TK_NUMBER"
  4621. end
  4622. ----------------------------------------------------------------
  4623. elseif c == "EOZ" then
  4624. return "TK_EOS"
  4625. ----------------------------------------------------------------
  4626. else -- default
  4627. if string.find(c, "%s") then
  4628. -- lua_assert(self:currIsNewline(ls))
  4629. self:nextc(ls)
  4630. elseif string.find(c, "%d") then
  4631. self:read_numeral(ls, Token)
  4632. return "TK_NUMBER"
  4633. elseif string.find(c, "[_%a]") then
  4634. -- identifier or reserved word
  4635. repeat
  4636. c = self:save_and_next(ls)
  4637. until c == "EOZ" or not string.find(c, "[_%w]")
  4638. local ts = ls.buff
  4639. local tok = self.enums[ts]
  4640. if tok then return tok end -- reserved word?
  4641. Token.seminfo = ts
  4642. return "TK_NAME"
  4643. else
  4644. self:nextc(ls)
  4645. return c -- single-char tokens (+ - / ...)
  4646. end
  4647. ----------------------------------------------------------------
  4648. end--if c
  4649. end--while
  4650. end
  4651.  
  4652. return luaX]]></ProtectedString>
  4653. <BinaryString name="Tags"></BinaryString>
  4654. </Properties>
  4655. </Item>
  4656. <Item class="ModuleScript" referent="RBX0C77EABDF4E04495A61E17E0F3651AB2">
  4657. <Properties>
  4658. <Content name="LinkedSource"><null></null></Content>
  4659. <string name="Name">LuaY</string>
  4660. <string name="ScriptGuid">{29BEDDC6-A318-4D8E-9DAB-C65576A9430E}</string>
  4661. <ProtectedString name="Source"><![CDATA[--[[--------------------------------------------------------------------
  4662.  
  4663. lparser.lua
  4664. Lua 5 parser in Lua
  4665. This file is part of Yueliang.
  4666.  
  4667. Copyright (c) 2005-2007 Kein-Hong Man <[email protected]>
  4668. The COPYRIGHT file describes the conditions
  4669. under which this software may be distributed.
  4670.  
  4671. See the ChangeLog for more information.
  4672.  
  4673. ----------------------------------------------------------------------]]
  4674.  
  4675. --[[--------------------------------------------------------------------
  4676. -- Notes:
  4677. -- * some unused C code that were not converted are kept as comments
  4678. -- * LUA_COMPAT_VARARG option changed into a comment block
  4679. -- * for value/size specific code added, look for 'NOTE: '
  4680. --
  4681. -- Not implemented:
  4682. -- * luaX_newstring not needed by this Lua implementation
  4683. -- * luaG_checkcode() in assert is not currently implemented
  4684. --
  4685. -- Added:
  4686. -- * some constants added from various header files
  4687. -- * luaY.LUA_QS used in error_expected, check_match (from luaconf.h)
  4688. -- * luaY:LUA_QL needed for error messages (from luaconf.h)
  4689. -- * luaY:growvector (from lmem.h) -- skeleton only, limit checking
  4690. -- * luaY.SHRT_MAX (from <limits.h>) for registerlocalvar
  4691. -- * luaY:newproto (from lfunc.c)
  4692. -- * luaY:int2fb (from lobject.c)
  4693. -- * NOTE: HASARG_MASK, for implementing a VARARG_HASARG bit operation
  4694. -- * NOTE: value-specific code for VARARG_NEEDSARG to replace a bitop
  4695. --
  4696. -- Changed in 5.1.x:
  4697. -- * various code changes are not detailed...
  4698. -- * names of constants may have changed, e.g. added a LUAI_ prefix
  4699. -- * struct expkind: added VKNUM, VVARARG; VCALL's info changed?
  4700. -- * struct expdesc: added nval
  4701. -- * struct FuncState: upvalues data type changed to upvaldesc
  4702. -- * macro hasmultret is new
  4703. -- * function checklimit moved to parser from lexer
  4704. -- * functions anchor_token, errorlimit, checknext are new
  4705. -- * checknext is new, equivalent to 5.0.x's check, see check too
  4706. -- * luaY:next and luaY:lookahead moved to lexer
  4707. -- * break keyword no longer skipped in luaY:breakstat
  4708. -- * function new_localvarstr replaced by new_localvarliteral
  4709. -- * registerlocalvar limits local variables to SHRT_MAX
  4710. -- * create_local deleted, new_localvarliteral used instead
  4711. -- * constant LUAI_MAXUPVALUES increased to 60
  4712. -- * constants MAXPARAMS, LUA_MAXPARSERLEVEL, MAXSTACK removed
  4713. -- * function interface changed: singlevaraux, singlevar
  4714. -- * enterlevel and leavelevel uses nCcalls to track call depth
  4715. -- * added a name argument to main entry function, luaY:parser
  4716. -- * function luaY_index changed to yindex
  4717. -- * luaY:int2fb()'s table size encoding format has been changed
  4718. -- * luaY:log2() no longer needed for table constructors
  4719. -- * function code_params deleted, functionality folded in parlist
  4720. -- * vararg flags handling (is_vararg) changes; also see VARARG_*
  4721. -- * LUA_COMPATUPSYNTAX section for old-style upvalues removed
  4722. -- * repeatstat() calls chunk() instead of block()
  4723. -- * function interface changed: cond, test_then_block
  4724. -- * while statement implementation considerably simplified; MAXEXPWHILE
  4725. -- and EXTRAEXP no longer required, no limits to the complexity of a
  4726. -- while condition
  4727. -- * repeat, forbody statement implementation has major changes,
  4728. -- mostly due to new scoping behaviour of local variables
  4729. -- * OPR_MULT renamed to OPR_MUL
  4730. ----------------------------------------------------------------------]]
  4731.  
  4732. --requires luaP, luaX, luaK
  4733. local luaY = {}
  4734. local luaX = require(script.Parent.LuaX)
  4735. local luaK = require(script.Parent.LuaK)(luaY)
  4736. local luaP = require(script.Parent.LuaP)
  4737.  
  4738. --[[--------------------------------------------------------------------
  4739. -- Expression descriptor
  4740. -- * expkind changed to string constants; luaY:assignment was the only
  4741. -- function to use a relational operator with this enumeration
  4742. -- VVOID -- no value
  4743. -- VNIL -- no value
  4744. -- VTRUE -- no value
  4745. -- VFALSE -- no value
  4746. -- VK -- info = index of constant in 'k'
  4747. -- VKNUM -- nval = numerical value
  4748. -- VLOCAL -- info = local register
  4749. -- VUPVAL, -- info = index of upvalue in 'upvalues'
  4750. -- VGLOBAL -- info = index of table; aux = index of global name in 'k'
  4751. -- VINDEXED -- info = table register; aux = index register (or 'k')
  4752. -- VJMP -- info = instruction pc
  4753. -- VRELOCABLE -- info = instruction pc
  4754. -- VNONRELOC -- info = result register
  4755. -- VCALL -- info = instruction pc
  4756. -- VVARARG -- info = instruction pc
  4757. } ----------------------------------------------------------------------]]
  4758.  
  4759. --[[--------------------------------------------------------------------
  4760. -- * expdesc in Lua 5.1.x has a union u and another struct s; this Lua
  4761. -- implementation ignores all instances of u and s usage
  4762. -- struct expdesc:
  4763. -- k -- (enum: expkind)
  4764. -- info, aux -- (int, int)
  4765. -- nval -- (lua_Number)
  4766. -- t -- patch list of 'exit when true'
  4767. -- f -- patch list of 'exit when false'
  4768. ----------------------------------------------------------------------]]
  4769.  
  4770. --[[--------------------------------------------------------------------
  4771. -- struct upvaldesc:
  4772. -- k -- (lu_byte)
  4773. -- info -- (lu_byte)
  4774. ----------------------------------------------------------------------]]
  4775.  
  4776. --[[--------------------------------------------------------------------
  4777. -- state needed to generate code for a given function
  4778. -- struct FuncState:
  4779. -- f -- current function header (table: Proto)
  4780. -- h -- table to find (and reuse) elements in 'k' (table: Table)
  4781. -- prev -- enclosing function (table: FuncState)
  4782. -- ls -- lexical state (table: LexState)
  4783. -- L -- copy of the Lua state (table: lua_State)
  4784. -- bl -- chain of current blocks (table: BlockCnt)
  4785. -- pc -- next position to code (equivalent to 'ncode')
  4786. -- lasttarget -- 'pc' of last 'jump target'
  4787. -- jpc -- list of pending jumps to 'pc'
  4788. -- freereg -- first free register
  4789. -- nk -- number of elements in 'k'
  4790. -- np -- number of elements in 'p'
  4791. -- nlocvars -- number of elements in 'locvars'
  4792. -- nactvar -- number of active local variables
  4793. -- upvalues[LUAI_MAXUPVALUES] -- upvalues (table: upvaldesc)
  4794. -- actvar[LUAI_MAXVARS] -- declared-variable stack
  4795. ----------------------------------------------------------------------]]
  4796.  
  4797. ------------------------------------------------------------------------
  4798. -- constants used by parser
  4799. -- * picks up duplicate values from luaX if required
  4800. ------------------------------------------------------------------------
  4801.  
  4802. luaY.LUA_QS = luaX.LUA_QS or "'%s'" -- (from luaconf.h)
  4803.  
  4804. luaY.SHRT_MAX = 32767 -- (from <limits.h>)
  4805. luaY.LUAI_MAXVARS = 200 -- (luaconf.h)
  4806. luaY.LUAI_MAXUPVALUES = 60 -- (luaconf.h)
  4807. luaY.MAX_INT = luaX.MAX_INT or 2147483645 -- (from llimits.h)
  4808. -- * INT_MAX-2 for 32-bit systems
  4809. luaY.LUAI_MAXCCALLS = 200 -- (from luaconf.h)
  4810.  
  4811. luaY.VARARG_HASARG = 1 -- (from lobject.h)
  4812. -- NOTE: HASARG_MASK is value-specific
  4813. luaY.HASARG_MASK = 2 -- this was added for a bitop in parlist()
  4814. luaY.VARARG_ISVARARG = 2
  4815. -- NOTE: there is some value-specific code that involves VARARG_NEEDSARG
  4816. luaY.VARARG_NEEDSARG = 4
  4817.  
  4818. luaY.LUA_MULTRET = -1 -- (lua.h)
  4819.  
  4820. --[[--------------------------------------------------------------------
  4821. -- other functions
  4822. ----------------------------------------------------------------------]]
  4823.  
  4824. ------------------------------------------------------------------------
  4825. -- LUA_QL describes how error messages quote program elements.
  4826. -- CHANGE it if you want a different appearance. (from luaconf.h)
  4827. ------------------------------------------------------------------------
  4828. function luaY:LUA_QL(x)
  4829. return "'"..x.."'"
  4830. end
  4831.  
  4832. ------------------------------------------------------------------------
  4833. -- this is a stripped-down luaM_growvector (from lmem.h) which is a
  4834. -- macro based on luaM_growaux (in lmem.c); all the following does is
  4835. -- reproduce the size limit checking logic of the original function
  4836. -- so that error behaviour is identical; all arguments preserved for
  4837. -- convenience, even those which are unused
  4838. -- * set the t field to nil, since this originally does a sizeof(t)
  4839. -- * size (originally a pointer) is never updated, their final values
  4840. -- are set by luaY:close_func(), so overall things should still work
  4841. ------------------------------------------------------------------------
  4842. function luaY:growvector(L, v, nelems, size, t, limit, e)
  4843. if nelems >= limit then
  4844. error(e) -- was luaG_runerror
  4845. end
  4846. end
  4847.  
  4848. ------------------------------------------------------------------------
  4849. -- initialize a new function prototype structure (from lfunc.c)
  4850. -- * used only in open_func()
  4851. ------------------------------------------------------------------------
  4852. function luaY:newproto(L)
  4853. local f = {} -- Proto
  4854. -- luaC_link(L, obj2gco(f), LUA_TPROTO); /* GC */
  4855. f.k = {}
  4856. f.sizek = 0
  4857. f.p = {}
  4858. f.sizep = 0
  4859. f.code = {}
  4860. f.sizecode = 0
  4861. f.sizelineinfo = 0
  4862. f.sizeupvalues = 0
  4863. f.nups = 0
  4864. f.upvalues = {}
  4865. f.numparams = 0
  4866. f.is_vararg = 0
  4867. f.maxstacksize = 0
  4868. f.lineinfo = {}
  4869. f.sizelocvars = 0
  4870. f.locvars = {}
  4871. f.lineDefined = 0
  4872. f.lastlinedefined = 0
  4873. f.source = nil
  4874. return f
  4875. end
  4876.  
  4877. ------------------------------------------------------------------------
  4878. -- converts an integer to a "floating point byte", represented as
  4879. -- (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
  4880. -- eeeee != 0 and (xxx) otherwise.
  4881. ------------------------------------------------------------------------
  4882. function luaY:int2fb(x)
  4883. local e = 0 -- exponent
  4884. while x >= 16 do
  4885. x = math.floor((x + 1) / 2)
  4886. e = e + 1
  4887. end
  4888. if x < 8 then
  4889. return x
  4890. else
  4891. return ((e + 1) * 8) + (x - 8)
  4892. end
  4893. end
  4894.  
  4895. --[[--------------------------------------------------------------------
  4896. -- parser functions
  4897. ----------------------------------------------------------------------]]
  4898.  
  4899. ------------------------------------------------------------------------
  4900. -- true of the kind of expression produces multiple return values
  4901. ------------------------------------------------------------------------
  4902. function luaY:hasmultret(k)
  4903. return k == "VCALL" or k == "VVARARG"
  4904. end
  4905.  
  4906. ------------------------------------------------------------------------
  4907. -- convenience function to access active local i, returns entry
  4908. ------------------------------------------------------------------------
  4909. function luaY:getlocvar(fs, i)
  4910. return fs.f.locvars[ fs.actvar[i] ]
  4911. end
  4912.  
  4913. ------------------------------------------------------------------------
  4914. -- check a limit, string m provided as an error message
  4915. ------------------------------------------------------------------------
  4916. function luaY:checklimit(fs, v, l, m)
  4917. if v > l then self:errorlimit(fs, l, m) end
  4918. end
  4919.  
  4920. --[[--------------------------------------------------------------------
  4921. -- nodes for block list (list of active blocks)
  4922. -- struct BlockCnt:
  4923. -- previous -- chain (table: BlockCnt)
  4924. -- breaklist -- list of jumps out of this loop
  4925. -- nactvar -- # active local variables outside the breakable structure
  4926. -- upval -- true if some variable in the block is an upvalue (boolean)
  4927. -- isbreakable -- true if 'block' is a loop (boolean)
  4928. ----------------------------------------------------------------------]]
  4929.  
  4930. ------------------------------------------------------------------------
  4931. -- prototypes for recursive non-terminal functions
  4932. ------------------------------------------------------------------------
  4933. -- prototypes deleted; not required in Lua
  4934.  
  4935. ------------------------------------------------------------------------
  4936. -- reanchor if last token is has a constant string, see close_func()
  4937. -- * used only in close_func()
  4938. ------------------------------------------------------------------------
  4939. function luaY:anchor_token(ls)
  4940. if ls.t.token == "TK_NAME" or ls.t.token == "TK_STRING" then
  4941. -- not relevant to Lua implementation of parser
  4942. -- local ts = ls.t.seminfo
  4943. -- luaX_newstring(ls, getstr(ts), ts->tsv.len); /* C */
  4944. end
  4945. end
  4946.  
  4947. ------------------------------------------------------------------------
  4948. -- throws a syntax error if token expected is not there
  4949. ------------------------------------------------------------------------
  4950. function luaY:error_expected(ls, token)
  4951. luaX:syntaxerror(ls,
  4952. string.format(self.LUA_QS.." expected", luaX:token2str(ls, token)))
  4953. end
  4954.  
  4955. ------------------------------------------------------------------------
  4956. -- prepares error message for display, for limits exceeded
  4957. -- * used only in checklimit()
  4958. ------------------------------------------------------------------------
  4959. function luaY:errorlimit(fs, limit, what)
  4960. local msg = (fs.f.linedefined == 0) and
  4961. string.format("main function has more than %d %s", limit, what) or
  4962. string.format("function at line %d has more than %d %s",
  4963. fs.f.linedefined, limit, what)
  4964. luaX:lexerror(fs.ls, msg, 0)
  4965. end
  4966.  
  4967. ------------------------------------------------------------------------
  4968. -- tests for a token, returns outcome
  4969. -- * return value changed to boolean
  4970. ------------------------------------------------------------------------
  4971. function luaY:testnext(ls, c)
  4972. if ls.t.token == c then
  4973. luaX:next(ls)
  4974. return true
  4975. else
  4976. return false
  4977. end
  4978. end
  4979.  
  4980. ------------------------------------------------------------------------
  4981. -- check for existence of a token, throws error if not found
  4982. ------------------------------------------------------------------------
  4983. function luaY:check(ls, c)
  4984. if ls.t.token ~= c then
  4985. self:error_expected(ls, c)
  4986. end
  4987. end
  4988.  
  4989. ------------------------------------------------------------------------
  4990. -- verify existence of a token, then skip it
  4991. ------------------------------------------------------------------------
  4992. function luaY:checknext(ls, c)
  4993. self:check(ls, c)
  4994. luaX:next(ls)
  4995. end
  4996.  
  4997. ------------------------------------------------------------------------
  4998. -- throws error if condition not matched
  4999. ------------------------------------------------------------------------
  5000. function luaY:check_condition(ls, c, msg)
  5001. if not c then luaX:syntaxerror(ls, msg) end
  5002. end
  5003.  
  5004. ------------------------------------------------------------------------
  5005. -- verifies token conditions are met or else throw error
  5006. ------------------------------------------------------------------------
  5007. function luaY:check_match(ls, what, who, where)
  5008. if not self:testnext(ls, what) then
  5009. if where == ls.linenumber then
  5010. self:error_expected(ls, what)
  5011. else
  5012. luaX:syntaxerror(ls, string.format(
  5013. self.LUA_QS.." expected (to close "..self.LUA_QS.." at line %d)",
  5014. luaX:token2str(ls, what), luaX:token2str(ls, who), where))
  5015. end
  5016. end
  5017. end
  5018.  
  5019. ------------------------------------------------------------------------
  5020. -- expect that token is a name, return the name
  5021. ------------------------------------------------------------------------
  5022. function luaY:str_checkname(ls)
  5023. self:check(ls, "TK_NAME")
  5024. local ts = ls.t.seminfo
  5025. luaX:next(ls)
  5026. return ts
  5027. end
  5028.  
  5029. ------------------------------------------------------------------------
  5030. -- initialize a struct expdesc, expression description data structure
  5031. ------------------------------------------------------------------------
  5032. function luaY:init_exp(e, k, i)
  5033. e.f, e.t = luaK.NO_JUMP, luaK.NO_JUMP
  5034. e.k = k
  5035. e.info = i
  5036. end
  5037.  
  5038. ------------------------------------------------------------------------
  5039. -- adds given string s in string pool, sets e as VK
  5040. ------------------------------------------------------------------------
  5041. function luaY:codestring(ls, e, s)
  5042. self:init_exp(e, "VK", luaK:stringK(ls.fs, s))
  5043. end
  5044.  
  5045. ------------------------------------------------------------------------
  5046. -- consume a name token, adds it to string pool, sets e as VK
  5047. ------------------------------------------------------------------------
  5048. function luaY:checkname(ls, e)
  5049. self:codestring(ls, e, self:str_checkname(ls))
  5050. end
  5051.  
  5052. ------------------------------------------------------------------------
  5053. -- creates struct entry for a local variable
  5054. -- * used only in new_localvar()
  5055. ------------------------------------------------------------------------
  5056. function luaY:registerlocalvar(ls, varname)
  5057. local fs = ls.fs
  5058. local f = fs.f
  5059. self:growvector(ls.L, f.locvars, fs.nlocvars, f.sizelocvars,
  5060. nil, self.SHRT_MAX, "too many local variables")
  5061. -- loop to initialize empty f.locvar positions not required
  5062. f.locvars[fs.nlocvars] = {} -- LocVar
  5063. f.locvars[fs.nlocvars].varname = varname
  5064. -- luaC_objbarrier(ls.L, f, varname) /* GC */
  5065. local nlocvars = fs.nlocvars
  5066. fs.nlocvars = fs.nlocvars + 1
  5067. return nlocvars
  5068. end
  5069.  
  5070. ------------------------------------------------------------------------
  5071. -- creates a new local variable given a name and an offset from nactvar
  5072. -- * used in fornum(), forlist(), parlist(), body()
  5073. ------------------------------------------------------------------------
  5074. function luaY:new_localvarliteral(ls, v, n)
  5075. self:new_localvar(ls, v, n)
  5076. end
  5077.  
  5078. ------------------------------------------------------------------------
  5079. -- register a local variable, set in active variable list
  5080. ------------------------------------------------------------------------
  5081. function luaY:new_localvar(ls, name, n)
  5082. local fs = ls.fs
  5083. self:checklimit(fs, fs.nactvar + n + 1, self.LUAI_MAXVARS, "local variables")
  5084. fs.actvar[fs.nactvar + n] = self:registerlocalvar(ls, name)
  5085. end
  5086.  
  5087. ------------------------------------------------------------------------
  5088. -- adds nvars number of new local variables, set debug information
  5089. ------------------------------------------------------------------------
  5090. function luaY:adjustlocalvars(ls, nvars)
  5091. local fs = ls.fs
  5092. fs.nactvar = fs.nactvar + nvars
  5093. for i = nvars, 1, -1 do
  5094. self:getlocvar(fs, fs.nactvar - i).startpc = fs.pc
  5095. end
  5096. end
  5097.  
  5098. ------------------------------------------------------------------------
  5099. -- removes a number of locals, set debug information
  5100. ------------------------------------------------------------------------
  5101. function luaY:removevars(ls, tolevel)
  5102. local fs = ls.fs
  5103. while fs.nactvar > tolevel do
  5104. fs.nactvar = fs.nactvar - 1
  5105. self:getlocvar(fs, fs.nactvar).endpc = fs.pc
  5106. end
  5107. end
  5108.  
  5109. ------------------------------------------------------------------------
  5110. -- returns an existing upvalue index based on the given name, or
  5111. -- creates a new upvalue struct entry and returns the new index
  5112. -- * used only in singlevaraux()
  5113. ------------------------------------------------------------------------
  5114. function luaY:indexupvalue(fs, name, v)
  5115. local f = fs.f
  5116. for i = 0, f.nups - 1 do
  5117. if fs.upvalues[i].k == v.k and fs.upvalues[i].info == v.info then
  5118. assert(f.upvalues[i] == name)
  5119. return i
  5120. end
  5121. end
  5122. -- new one
  5123. self:checklimit(fs, f.nups + 1, self.LUAI_MAXUPVALUES, "upvalues")
  5124. self:growvector(fs.L, f.upvalues, f.nups, f.sizeupvalues,
  5125. nil, self.MAX_INT, "")
  5126. -- loop to initialize empty f.upvalues positions not required
  5127. f.upvalues[f.nups] = name
  5128. -- luaC_objbarrier(fs->L, f, name); /* GC */
  5129. assert(v.k == "VLOCAL" or v.k == "VUPVAL")
  5130. -- this is a partial copy; only k & info fields used
  5131. fs.upvalues[f.nups] = { k = v.k, info = v.info }
  5132. local nups = f.nups
  5133. f.nups = f.nups + 1
  5134. return nups
  5135. end
  5136.  
  5137. ------------------------------------------------------------------------
  5138. -- search the local variable namespace of the given fs for a match
  5139. -- * used only in singlevaraux()
  5140. ------------------------------------------------------------------------
  5141. function luaY:searchvar(fs, n)
  5142. for i = fs.nactvar - 1, 0, -1 do
  5143. if n == self:getlocvar(fs, i).varname then
  5144. return i
  5145. end
  5146. end
  5147. return -1 -- not found
  5148. end
  5149.  
  5150. ------------------------------------------------------------------------
  5151. -- * mark upvalue flags in function states up to a given level
  5152. -- * used only in singlevaraux()
  5153. ------------------------------------------------------------------------
  5154. function luaY:markupval(fs, level)
  5155. local bl = fs.bl
  5156. while bl and bl.nactvar > level do bl = bl.previous end
  5157. if bl then bl.upval = true end
  5158. end
  5159.  
  5160. ------------------------------------------------------------------------
  5161. -- handle locals, globals and upvalues and related processing
  5162. -- * search mechanism is recursive, calls itself to search parents
  5163. -- * used only in singlevar()
  5164. ------------------------------------------------------------------------
  5165. function luaY:singlevaraux(fs, n, var, base)
  5166. if fs == nil then -- no more levels?
  5167. self:init_exp(var, "VGLOBAL", luaP.NO_REG) -- default is global variable
  5168. return "VGLOBAL"
  5169. else
  5170. local v = self:searchvar(fs, n) -- look up at current level
  5171. if v >= 0 then
  5172. self:init_exp(var, "VLOCAL", v)
  5173. if base == 0 then
  5174. self:markupval(fs, v) -- local will be used as an upval
  5175. end
  5176. return "VLOCAL"
  5177. else -- not found at current level; try upper one
  5178. if self:singlevaraux(fs.prev, n, var, 0) == "VGLOBAL" then
  5179. return "VGLOBAL"
  5180. end
  5181. var.info = self:indexupvalue(fs, n, var) -- else was LOCAL or UPVAL
  5182. var.k = "VUPVAL" -- upvalue in this level
  5183. return "VUPVAL"
  5184. end--if v
  5185. end--if fs
  5186. end
  5187.  
  5188. ------------------------------------------------------------------------
  5189. -- consume a name token, creates a variable (global|local|upvalue)
  5190. -- * used in prefixexp(), funcname()
  5191. ------------------------------------------------------------------------
  5192. function luaY:singlevar(ls, var)
  5193. local varname = self:str_checkname(ls)
  5194. local fs = ls.fs
  5195. if self:singlevaraux(fs, varname, var, 1) == "VGLOBAL" then
  5196. var.info = luaK:stringK(fs, varname) -- info points to global name
  5197. end
  5198. end
  5199.  
  5200. ------------------------------------------------------------------------
  5201. -- adjust RHS to match LHS in an assignment
  5202. -- * used in assignment(), forlist(), localstat()
  5203. ------------------------------------------------------------------------
  5204. function luaY:adjust_assign(ls, nvars, nexps, e)
  5205. local fs = ls.fs
  5206. local extra = nvars - nexps
  5207. if self:hasmultret(e.k) then
  5208. extra = extra + 1 -- includes call itself
  5209. if extra <= 0 then extra = 0 end
  5210. luaK:setreturns(fs, e, extra) -- last exp. provides the difference
  5211. if extra > 1 then luaK:reserveregs(fs, extra - 1) end
  5212. else
  5213. if e.k ~= "VVOID" then luaK:exp2nextreg(fs, e) end -- close last expression
  5214. if extra > 0 then
  5215. local reg = fs.freereg
  5216. luaK:reserveregs(fs, extra)
  5217. luaK:_nil(fs, reg, extra)
  5218. end
  5219. end
  5220. end
  5221.  
  5222. ------------------------------------------------------------------------
  5223. -- tracks and limits parsing depth, assert check at end of parsing
  5224. ------------------------------------------------------------------------
  5225. function luaY:enterlevel(ls)
  5226. ls.L.nCcalls = ls.L.nCcalls + 1
  5227. if ls.L.nCcalls > self.LUAI_MAXCCALLS then
  5228. luaX:lexerror(ls, "chunk has too many syntax levels", 0)
  5229. end
  5230. end
  5231.  
  5232. ------------------------------------------------------------------------
  5233. -- tracks parsing depth, a pair with luaY:enterlevel()
  5234. ------------------------------------------------------------------------
  5235. function luaY:leavelevel(ls)
  5236. ls.L.nCcalls = ls.L.nCcalls - 1
  5237. end
  5238.  
  5239. ------------------------------------------------------------------------
  5240. -- enters a code unit, initializes elements
  5241. ------------------------------------------------------------------------
  5242. function luaY:enterblock(fs, bl, isbreakable)
  5243. bl.breaklist = luaK.NO_JUMP
  5244. bl.isbreakable = isbreakable
  5245. bl.nactvar = fs.nactvar
  5246. bl.upval = false
  5247. bl.previous = fs.bl
  5248. fs.bl = bl
  5249. assert(fs.freereg == fs.nactvar)
  5250. end
  5251.  
  5252. ------------------------------------------------------------------------
  5253. -- leaves a code unit, close any upvalues
  5254. ------------------------------------------------------------------------
  5255. function luaY:leaveblock(fs)
  5256. local bl = fs.bl
  5257. fs.bl = bl.previous
  5258. self:removevars(fs.ls, bl.nactvar)
  5259. if bl.upval then
  5260. luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
  5261. end
  5262. -- a block either controls scope or breaks (never both)
  5263. assert(not bl.isbreakable or not bl.upval)
  5264. assert(bl.nactvar == fs.nactvar)
  5265. fs.freereg = fs.nactvar -- free registers
  5266. luaK:patchtohere(fs, bl.breaklist)
  5267. end
  5268.  
  5269. ------------------------------------------------------------------------
  5270. -- implement the instantiation of a function prototype, append list of
  5271. -- upvalues after the instantiation instruction
  5272. -- * used only in body()
  5273. ------------------------------------------------------------------------
  5274. function luaY:pushclosure(ls, func, v)
  5275. local fs = ls.fs
  5276. local f = fs.f
  5277. self:growvector(ls.L, f.p, fs.np, f.sizep, nil,
  5278. luaP.MAXARG_Bx, "constant table overflow")
  5279. -- loop to initialize empty f.p positions not required
  5280. f.p[fs.np] = func.f
  5281. fs.np = fs.np + 1
  5282. -- luaC_objbarrier(ls->L, f, func->f); /* C */
  5283. self:init_exp(v, "VRELOCABLE", luaK:codeABx(fs, "OP_CLOSURE", 0, fs.np - 1))
  5284. for i = 0, func.f.nups - 1 do
  5285. local o = (func.upvalues[i].k == "VLOCAL") and "OP_MOVE" or "OP_GETUPVAL"
  5286. luaK:codeABC(fs, o, 0, func.upvalues[i].info, 0)
  5287. end
  5288. end
  5289.  
  5290. ------------------------------------------------------------------------
  5291. -- opening of a function
  5292. ------------------------------------------------------------------------
  5293. function luaY:open_func(ls, fs)
  5294. local L = ls.L
  5295. local f = self:newproto(ls.L)
  5296. fs.f = f
  5297. fs.prev = ls.fs -- linked list of funcstates
  5298. fs.ls = ls
  5299. fs.L = L
  5300. ls.fs = fs
  5301. fs.pc = 0
  5302. fs.lasttarget = -1
  5303. fs.jpc = luaK.NO_JUMP
  5304. fs.freereg = 0
  5305. fs.nk = 0
  5306. fs.np = 0
  5307. fs.nlocvars = 0
  5308. fs.nactvar = 0
  5309. fs.bl = nil
  5310. f.source = ls.source
  5311. f.maxstacksize = 2 -- registers 0/1 are always valid
  5312. fs.h = {} -- constant table; was luaH_new call
  5313. -- anchor table of constants and prototype (to avoid being collected)
  5314. -- sethvalue2s(L, L->top, fs->h); incr_top(L); /* C */
  5315. -- setptvalue2s(L, L->top, f); incr_top(L);
  5316. end
  5317.  
  5318. ------------------------------------------------------------------------
  5319. -- closing of a function
  5320. ------------------------------------------------------------------------
  5321. function luaY:close_func(ls)
  5322. local L = ls.L
  5323. local fs = ls.fs
  5324. local f = fs.f
  5325. self:removevars(ls, 0)
  5326. luaK:ret(fs, 0, 0) -- final return
  5327. -- luaM_reallocvector deleted for f->code, f->lineinfo, f->k, f->p,
  5328. -- f->locvars, f->upvalues; not required for Lua table arrays
  5329. f.sizecode = fs.pc
  5330. f.sizelineinfo = fs.pc
  5331. f.sizek = fs.nk
  5332. f.sizep = fs.np
  5333. f.sizelocvars = fs.nlocvars
  5334. f.sizeupvalues = f.nups
  5335. --assert(luaG_checkcode(f)) -- currently not implemented
  5336. assert(fs.bl == nil)
  5337. ls.fs = fs.prev
  5338. -- the following is not required for this implementation; kept here
  5339. -- for completeness
  5340. -- L->top -= 2; /* remove table and prototype from the stack */
  5341. -- last token read was anchored in defunct function; must reanchor it
  5342. if fs then self:anchor_token(ls) end
  5343. end
  5344.  
  5345. ------------------------------------------------------------------------
  5346. -- parser initialization function
  5347. -- * note additional sub-tables needed for LexState, FuncState
  5348. ------------------------------------------------------------------------
  5349. function luaY:parser(L, z, buff, name)
  5350. local lexstate = {} -- LexState
  5351. lexstate.t = {}
  5352. lexstate.lookahead = {}
  5353. local funcstate = {} -- FuncState
  5354. funcstate.upvalues = {}
  5355. funcstate.actvar = {}
  5356. -- the following nCcalls initialization added for convenience
  5357. L.nCcalls = 0
  5358. lexstate.buff = buff
  5359. luaX:setinput(L, lexstate, z, name)
  5360. self:open_func(lexstate, funcstate)
  5361. funcstate.f.is_vararg = self.VARARG_ISVARARG -- main func. is always vararg
  5362. luaX:next(lexstate) -- read first token
  5363. self:chunk(lexstate)
  5364. self:check(lexstate, "TK_EOS")
  5365. self:close_func(lexstate)
  5366. assert(funcstate.prev == nil)
  5367. assert(funcstate.f.nups == 0)
  5368. assert(lexstate.fs == nil)
  5369. return funcstate.f
  5370. end
  5371.  
  5372. --[[--------------------------------------------------------------------
  5373. -- GRAMMAR RULES
  5374. ----------------------------------------------------------------------]]
  5375.  
  5376. ------------------------------------------------------------------------
  5377. -- parse a function name suffix, for function call specifications
  5378. -- * used in primaryexp(), funcname()
  5379. ------------------------------------------------------------------------
  5380. function luaY:field(ls, v)
  5381. -- field -> ['.' | ':'] NAME
  5382. local fs = ls.fs
  5383. local key = {} -- expdesc
  5384. luaK:exp2anyreg(fs, v)
  5385. luaX:next(ls) -- skip the dot or colon
  5386. self:checkname(ls, key)
  5387. luaK:indexed(fs, v, key)
  5388. end
  5389.  
  5390. ------------------------------------------------------------------------
  5391. -- parse a table indexing suffix, for constructors, expressions
  5392. -- * used in recfield(), primaryexp()
  5393. ------------------------------------------------------------------------
  5394. function luaY:yindex(ls, v)
  5395. -- index -> '[' expr ']'
  5396. luaX:next(ls) -- skip the '['
  5397. self:expr(ls, v)
  5398. luaK:exp2val(ls.fs, v)
  5399. self:checknext(ls, "]")
  5400. end
  5401.  
  5402. --[[--------------------------------------------------------------------
  5403. -- Rules for Constructors
  5404. ----------------------------------------------------------------------]]
  5405.  
  5406. --[[--------------------------------------------------------------------
  5407. -- struct ConsControl:
  5408. -- v -- last list item read (table: struct expdesc)
  5409. -- t -- table descriptor (table: struct expdesc)
  5410. -- nh -- total number of 'record' elements
  5411. -- na -- total number of array elements
  5412. -- tostore -- number of array elements pending to be stored
  5413. ----------------------------------------------------------------------]]
  5414.  
  5415. ------------------------------------------------------------------------
  5416. -- parse a table record (hash) field
  5417. -- * used in constructor()
  5418. ------------------------------------------------------------------------
  5419. function luaY:recfield(ls, cc)
  5420. -- recfield -> (NAME | '['exp1']') = exp1
  5421. local fs = ls.fs
  5422. local reg = ls.fs.freereg
  5423. local key, val = {}, {} -- expdesc
  5424. if ls.t.token == "TK_NAME" then
  5425. self:checklimit(fs, cc.nh, self.MAX_INT, "items in a constructor")
  5426. self:checkname(ls, key)
  5427. else -- ls->t.token == '['
  5428. self:yindex(ls, key)
  5429. end
  5430. cc.nh = cc.nh + 1
  5431. self:checknext(ls, "=")
  5432. local rkkey = luaK:exp2RK(fs, key)
  5433. self:expr(ls, val)
  5434. luaK:codeABC(fs, "OP_SETTABLE", cc.t.info, rkkey, luaK:exp2RK(fs, val))
  5435. fs.freereg = reg -- free registers
  5436. end
  5437.  
  5438. ------------------------------------------------------------------------
  5439. -- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH)
  5440. -- * used in constructor()
  5441. ------------------------------------------------------------------------
  5442. function luaY:closelistfield(fs, cc)
  5443. if cc.v.k == "VVOID" then return end -- there is no list item
  5444. luaK:exp2nextreg(fs, cc.v)
  5445. cc.v.k = "VVOID"
  5446. if cc.tostore == luaP.LFIELDS_PER_FLUSH then
  5447. luaK:setlist(fs, cc.t.info, cc.na, cc.tostore) -- flush
  5448. cc.tostore = 0 -- no more items pending
  5449. end
  5450. end
  5451.  
  5452. ------------------------------------------------------------------------
  5453. -- emit a set list instruction at the end of parsing list constructor
  5454. -- * used in constructor()
  5455. ------------------------------------------------------------------------
  5456. function luaY:lastlistfield(fs, cc)
  5457. if cc.tostore == 0 then return end
  5458. if self:hasmultret(cc.v.k) then
  5459. luaK:setmultret(fs, cc.v)
  5460. luaK:setlist(fs, cc.t.info, cc.na, self.LUA_MULTRET)
  5461. cc.na = cc.na - 1 -- do not count last expression (unknown number of elements)
  5462. else
  5463. if cc.v.k ~= "VVOID" then
  5464. luaK:exp2nextreg(fs, cc.v)
  5465. end
  5466. luaK:setlist(fs, cc.t.info, cc.na, cc.tostore)
  5467. end
  5468. end
  5469.  
  5470. ------------------------------------------------------------------------
  5471. -- parse a table list (array) field
  5472. -- * used in constructor()
  5473. ------------------------------------------------------------------------
  5474. function luaY:listfield(ls, cc)
  5475. self:expr(ls, cc.v)
  5476. self:checklimit(ls.fs, cc.na, self.MAX_INT, "items in a constructor")
  5477. cc.na = cc.na + 1
  5478. cc.tostore = cc.tostore + 1
  5479. end
  5480.  
  5481. ------------------------------------------------------------------------
  5482. -- parse a table constructor
  5483. -- * used in funcargs(), simpleexp()
  5484. ------------------------------------------------------------------------
  5485. function luaY:constructor(ls, t)
  5486. -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}'
  5487. -- field -> recfield | listfield
  5488. -- fieldsep -> ',' | ';'
  5489. local fs = ls.fs
  5490. local line = ls.linenumber
  5491. local pc = luaK:codeABC(fs, "OP_NEWTABLE", 0, 0, 0)
  5492. local cc = {} -- ConsControl
  5493. cc.v = {}
  5494. cc.na, cc.nh, cc.tostore = 0, 0, 0
  5495. cc.t = t
  5496. self:init_exp(t, "VRELOCABLE", pc)
  5497. self:init_exp(cc.v, "VVOID", 0) -- no value (yet)
  5498. luaK:exp2nextreg(ls.fs, t) -- fix it at stack top (for gc)
  5499. self:checknext(ls, "{")
  5500. repeat
  5501. assert(cc.v.k == "VVOID" or cc.tostore > 0)
  5502. if ls.t.token == "}" then break end
  5503. self:closelistfield(fs, cc)
  5504. local c = ls.t.token
  5505.  
  5506. if c == "TK_NAME" then -- may be listfields or recfields
  5507. luaX:lookahead(ls)
  5508. if ls.lookahead.token ~= "=" then -- expression?
  5509. self:listfield(ls, cc)
  5510. else
  5511. self:recfield(ls, cc)
  5512. end
  5513. elseif c == "[" then -- constructor_item -> recfield
  5514. self:recfield(ls, cc)
  5515. else -- constructor_part -> listfield
  5516. self:listfield(ls, cc)
  5517. end
  5518. until not self:testnext(ls, ",") and not self:testnext(ls, ";")
  5519. self:check_match(ls, "}", "{", line)
  5520. self:lastlistfield(fs, cc)
  5521. luaP:SETARG_B(fs.f.code[pc], self:int2fb(cc.na)) -- set initial array size
  5522. luaP:SETARG_C(fs.f.code[pc], self:int2fb(cc.nh)) -- set initial table size
  5523. end
  5524.  
  5525. -- }======================================================================
  5526.  
  5527. ------------------------------------------------------------------------
  5528. -- parse the arguments (parameters) of a function declaration
  5529. -- * used in body()
  5530. ------------------------------------------------------------------------
  5531. function luaY:parlist(ls)
  5532. -- parlist -> [ param { ',' param } ]
  5533. local fs = ls.fs
  5534. local f = fs.f
  5535. local nparams = 0
  5536. f.is_vararg = 0
  5537. if ls.t.token ~= ")" then -- is 'parlist' not empty?
  5538. repeat
  5539. local c = ls.t.token
  5540. if c == "TK_NAME" then -- param -> NAME
  5541. self:new_localvar(ls, self:str_checkname(ls), nparams)
  5542. nparams = nparams + 1
  5543. elseif c == "TK_DOTS" then -- param -> `...'
  5544. luaX:next(ls)
  5545. -- [[
  5546. -- #if defined(LUA_COMPAT_VARARG)
  5547. -- use `arg' as default name
  5548. self:new_localvarliteral(ls, "arg", nparams)
  5549. nparams = nparams + 1
  5550. f.is_vararg = self.VARARG_HASARG + self.VARARG_NEEDSARG
  5551. -- #endif
  5552. --]]
  5553. f.is_vararg = f.is_vararg + self.VARARG_ISVARARG
  5554. else
  5555. luaX:syntaxerror(ls, "<name> or "..self:LUA_QL("...").." expected")
  5556. end
  5557. until f.is_vararg ~= 0 or not self:testnext(ls, ",")
  5558. end--if
  5559. self:adjustlocalvars(ls, nparams)
  5560. -- NOTE: the following works only when HASARG_MASK is 2!
  5561. f.numparams = fs.nactvar - (f.is_vararg % self.HASARG_MASK)
  5562. luaK:reserveregs(fs, fs.nactvar) -- reserve register for parameters
  5563. end
  5564.  
  5565. ------------------------------------------------------------------------
  5566. -- parse function declaration body
  5567. -- * used in simpleexp(), localfunc(), funcstat()
  5568. ------------------------------------------------------------------------
  5569. function luaY:body(ls, e, needself, line)
  5570. -- body -> '(' parlist ')' chunk END
  5571. local new_fs = {} -- FuncState
  5572. new_fs.upvalues = {}
  5573. new_fs.actvar = {}
  5574. self:open_func(ls, new_fs)
  5575. new_fs.f.lineDefined = line
  5576. self:checknext(ls, "(")
  5577. if needself then
  5578. self:new_localvarliteral(ls, "self", 0)
  5579. self:adjustlocalvars(ls, 1)
  5580. end
  5581. self:parlist(ls)
  5582. self:checknext(ls, ")")
  5583. self:chunk(ls)
  5584. new_fs.f.lastlinedefined = ls.linenumber
  5585. self:check_match(ls, "TK_END", "TK_FUNCTION", line)
  5586. self:close_func(ls)
  5587. self:pushclosure(ls, new_fs, e)
  5588. end
  5589.  
  5590. ------------------------------------------------------------------------
  5591. -- parse a list of comma-separated expressions
  5592. -- * used is multiple locations
  5593. ------------------------------------------------------------------------
  5594. function luaY:explist1(ls, v)
  5595. -- explist1 -> expr { ',' expr }
  5596. local n = 1 -- at least one expression
  5597. self:expr(ls, v)
  5598. while self:testnext(ls, ",") do
  5599. luaK:exp2nextreg(ls.fs, v)
  5600. self:expr(ls, v)
  5601. n = n + 1
  5602. end
  5603. return n
  5604. end
  5605.  
  5606. ------------------------------------------------------------------------
  5607. -- parse the parameters of a function call
  5608. -- * contrast with parlist(), used in function declarations
  5609. -- * used in primaryexp()
  5610. ------------------------------------------------------------------------
  5611. function luaY:funcargs(ls, f)
  5612. local fs = ls.fs
  5613. local args = {} -- expdesc
  5614. local nparams
  5615. local line = ls.linenumber
  5616. local c = ls.t.token
  5617. if c == "(" then -- funcargs -> '(' [ explist1 ] ')'
  5618. if line ~= ls.lastline then
  5619. luaX:syntaxerror(ls, "ambiguous syntax (function call x new statement)")
  5620. end
  5621. luaX:next(ls)
  5622. if ls.t.token == ")" then -- arg list is empty?
  5623. args.k = "VVOID"
  5624. else
  5625. self:explist1(ls, args)
  5626. luaK:setmultret(fs, args)
  5627. end
  5628. self:check_match(ls, ")", "(", line)
  5629. elseif c == "{" then -- funcargs -> constructor
  5630. self:constructor(ls, args)
  5631. elseif c == "TK_STRING" then -- funcargs -> STRING
  5632. self:codestring(ls, args, ls.t.seminfo)
  5633. luaX:next(ls) -- must use 'seminfo' before 'next'
  5634. else
  5635. luaX:syntaxerror(ls, "function arguments expected")
  5636. return
  5637. end
  5638. assert(f.k == "VNONRELOC")
  5639. local base = f.info -- base register for call
  5640. if self:hasmultret(args.k) then
  5641. nparams = self.LUA_MULTRET -- open call
  5642. else
  5643. if args.k ~= "VVOID" then
  5644. luaK:exp2nextreg(fs, args) -- close last argument
  5645. end
  5646. nparams = fs.freereg - (base + 1)
  5647. end
  5648. self:init_exp(f, "VCALL", luaK:codeABC(fs, "OP_CALL", base, nparams + 1, 2))
  5649. luaK:fixline(fs, line)
  5650. fs.freereg = base + 1 -- call remove function and arguments and leaves
  5651. -- (unless changed) one result
  5652. end
  5653.  
  5654. --[[--------------------------------------------------------------------
  5655. -- Expression parsing
  5656. ----------------------------------------------------------------------]]
  5657.  
  5658. ------------------------------------------------------------------------
  5659. -- parses an expression in parentheses or a single variable
  5660. -- * used in primaryexp()
  5661. ------------------------------------------------------------------------
  5662. function luaY:prefixexp(ls, v)
  5663. -- prefixexp -> NAME | '(' expr ')'
  5664. local c = ls.t.token
  5665. if c == "(" then
  5666. local line = ls.linenumber
  5667. luaX:next(ls)
  5668. self:expr(ls, v)
  5669. self:check_match(ls, ")", "(", line)
  5670. luaK:dischargevars(ls.fs, v)
  5671. elseif c == "TK_NAME" then
  5672. self:singlevar(ls, v)
  5673. else
  5674. luaX:syntaxerror(ls, "unexpected symbol")
  5675. end--if c
  5676. return
  5677. end
  5678.  
  5679. ------------------------------------------------------------------------
  5680. -- parses a prefixexp (an expression in parentheses or a single variable)
  5681. -- or a function call specification
  5682. -- * used in simpleexp(), assignment(), exprstat()
  5683. ------------------------------------------------------------------------
  5684. function luaY:primaryexp(ls, v)
  5685. -- primaryexp ->
  5686. -- prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
  5687. local fs = ls.fs
  5688. self:prefixexp(ls, v)
  5689. while true do
  5690. local c = ls.t.token
  5691. if c == "." then -- field
  5692. self:field(ls, v)
  5693. elseif c == "[" then -- '[' exp1 ']'
  5694. local key = {} -- expdesc
  5695. luaK:exp2anyreg(fs, v)
  5696. self:yindex(ls, key)
  5697. luaK:indexed(fs, v, key)
  5698. elseif c == ":" then -- ':' NAME funcargs
  5699. local key = {} -- expdesc
  5700. luaX:next(ls)
  5701. self:checkname(ls, key)
  5702. luaK:_self(fs, v, key)
  5703. self:funcargs(ls, v)
  5704. elseif c == "(" or c == "TK_STRING" or c == "{" then -- funcargs
  5705. luaK:exp2nextreg(fs, v)
  5706. self:funcargs(ls, v)
  5707. else
  5708. return
  5709. end--if c
  5710. end--while
  5711. end
  5712.  
  5713. ------------------------------------------------------------------------
  5714. -- parses general expression types, constants handled here
  5715. -- * used in subexpr()
  5716. ------------------------------------------------------------------------
  5717. function luaY:simpleexp(ls, v)
  5718. -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
  5719. -- constructor | FUNCTION body | primaryexp
  5720. local c = ls.t.token
  5721. if c == "TK_NUMBER" then
  5722. self:init_exp(v, "VKNUM", 0)
  5723. v.nval = ls.t.seminfo
  5724. elseif c == "TK_STRING" then
  5725. self:codestring(ls, v, ls.t.seminfo)
  5726. elseif c == "TK_NIL" then
  5727. self:init_exp(v, "VNIL", 0)
  5728. elseif c == "TK_TRUE" then
  5729. self:init_exp(v, "VTRUE", 0)
  5730. elseif c == "TK_FALSE" then
  5731. self:init_exp(v, "VFALSE", 0)
  5732. elseif c == "TK_DOTS" then -- vararg
  5733. local fs = ls.fs
  5734. self:check_condition(ls, fs.f.is_vararg ~= 0,
  5735. "cannot use "..self:LUA_QL("...").." outside a vararg function");
  5736. -- NOTE: the following substitutes for a bitop, but is value-specific
  5737. local is_vararg = fs.f.is_vararg
  5738. if is_vararg >= self.VARARG_NEEDSARG then
  5739. fs.f.is_vararg = is_vararg - self.VARARG_NEEDSARG -- don't need 'arg'
  5740. end
  5741. self:init_exp(v, "VVARARG", luaK:codeABC(fs, "OP_VARARG", 0, 1, 0))
  5742. elseif c == "{" then -- constructor
  5743. self:constructor(ls, v)
  5744. return
  5745. elseif c == "TK_FUNCTION" then
  5746. luaX:next(ls)
  5747. self:body(ls, v, false, ls.linenumber)
  5748. return
  5749. else
  5750. self:primaryexp(ls, v)
  5751. return
  5752. end--if c
  5753. luaX:next(ls)
  5754. end
  5755.  
  5756. ------------------------------------------------------------------------
  5757. -- Translates unary operators tokens if found, otherwise returns
  5758. -- OPR_NOUNOPR. getunopr() and getbinopr() are used in subexpr().
  5759. -- * used in subexpr()
  5760. ------------------------------------------------------------------------
  5761. function luaY:getunopr(op)
  5762. if op == "TK_NOT" then
  5763. return "OPR_NOT"
  5764. elseif op == "-" then
  5765. return "OPR_MINUS"
  5766. elseif op == "#" then
  5767. return "OPR_LEN"
  5768. else
  5769. return "OPR_NOUNOPR"
  5770. end
  5771. end
  5772.  
  5773. ------------------------------------------------------------------------
  5774. -- Translates binary operator tokens if found, otherwise returns
  5775. -- OPR_NOBINOPR. Code generation uses OPR_* style tokens.
  5776. -- * used in subexpr()
  5777. ------------------------------------------------------------------------
  5778. luaY.getbinopr_table = {
  5779. ["+"] = "OPR_ADD",
  5780. ["-"] = "OPR_SUB",
  5781. ["*"] = "OPR_MUL",
  5782. ["/"] = "OPR_DIV",
  5783. ["%"] = "OPR_MOD",
  5784. ["^"] = "OPR_POW",
  5785. ["TK_CONCAT"] = "OPR_CONCAT",
  5786. ["TK_NE"] = "OPR_NE",
  5787. ["TK_EQ"] = "OPR_EQ",
  5788. ["<"] = "OPR_LT",
  5789. ["TK_LE"] = "OPR_LE",
  5790. [">"] = "OPR_GT",
  5791. ["TK_GE"] = "OPR_GE",
  5792. ["TK_AND"] = "OPR_AND",
  5793. ["TK_OR"] = "OPR_OR",
  5794. }
  5795. function luaY:getbinopr(op)
  5796. local opr = self.getbinopr_table[op]
  5797. if opr then return opr else return "OPR_NOBINOPR" end
  5798. end
  5799.  
  5800. ------------------------------------------------------------------------
  5801. -- the following priority table consists of pairs of left/right values
  5802. -- for binary operators (was a static const struct); grep for ORDER OPR
  5803. -- * the following struct is replaced:
  5804. -- static const struct {
  5805. -- lu_byte left; /* left priority for each binary operator */
  5806. -- lu_byte right; /* right priority */
  5807. -- } priority[] = { /* ORDER OPR */
  5808. ------------------------------------------------------------------------
  5809. luaY.priority = {
  5810. {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, -- `+' `-' `/' `%'
  5811. {10, 9}, {5, 4}, -- power and concat (right associative)
  5812. {3, 3}, {3, 3}, -- equality
  5813. {3, 3}, {3, 3}, {3, 3}, {3, 3}, -- order
  5814. {2, 2}, {1, 1} -- logical (and/or)
  5815. }
  5816.  
  5817. luaY.UNARY_PRIORITY = 8 -- priority for unary operators
  5818.  
  5819. ------------------------------------------------------------------------
  5820. -- Parse subexpressions. Includes handling of unary operators and binary
  5821. -- operators. A subexpr is given the rhs priority level of the operator
  5822. -- immediately left of it, if any (limit is -1 if none,) and if a binop
  5823. -- is found, limit is compared with the lhs priority level of the binop
  5824. -- in order to determine which executes first.
  5825. ------------------------------------------------------------------------
  5826.  
  5827. ------------------------------------------------------------------------
  5828. -- subexpr -> (simpleexp | unop subexpr) { binop subexpr }
  5829. -- where 'binop' is any binary operator with a priority higher than 'limit'
  5830. -- * for priority lookups with self.priority[], 1=left and 2=right
  5831. -- * recursively called
  5832. -- * used in expr()
  5833. ------------------------------------------------------------------------
  5834. function luaY:subexpr(ls, v, limit)
  5835. self:enterlevel(ls)
  5836. local uop = self:getunopr(ls.t.token)
  5837. if uop ~= "OPR_NOUNOPR" then
  5838. luaX:next(ls)
  5839. self:subexpr(ls, v, self.UNARY_PRIORITY)
  5840. luaK:prefix(ls.fs, uop, v)
  5841. else
  5842. self:simpleexp(ls, v)
  5843. end
  5844. -- expand while operators have priorities higher than 'limit'
  5845. local op = self:getbinopr(ls.t.token)
  5846. while op ~= "OPR_NOBINOPR" and self.priority[luaK.BinOpr[op] + 1][1] > limit do
  5847. local v2 = {} -- expdesc
  5848. luaX:next(ls)
  5849. luaK:infix(ls.fs, op, v)
  5850. -- read sub-expression with higher priority
  5851. local nextop = self:subexpr(ls, v2, self.priority[luaK.BinOpr[op] + 1][2])
  5852. luaK:posfix(ls.fs, op, v, v2)
  5853. op = nextop
  5854. end
  5855. self:leavelevel(ls)
  5856. return op -- return first untreated operator
  5857. end
  5858.  
  5859. ------------------------------------------------------------------------
  5860. -- Expression parsing starts here. Function subexpr is entered with the
  5861. -- left operator (which is non-existent) priority of -1, which is lower
  5862. -- than all actual operators. Expr information is returned in parm v.
  5863. -- * used in multiple locations
  5864. ------------------------------------------------------------------------
  5865. function luaY:expr(ls, v)
  5866. self:subexpr(ls, v, 0)
  5867. end
  5868.  
  5869. -- }====================================================================
  5870.  
  5871. --[[--------------------------------------------------------------------
  5872. -- Rules for Statements
  5873. ----------------------------------------------------------------------]]
  5874.  
  5875. ------------------------------------------------------------------------
  5876. -- checks next token, used as a look-ahead
  5877. -- * returns boolean instead of 0|1
  5878. -- * used in retstat(), chunk()
  5879. ------------------------------------------------------------------------
  5880. function luaY:block_follow(token)
  5881. if token == "TK_ELSE" or token == "TK_ELSEIF" or token == "TK_END"
  5882. or token == "TK_UNTIL" or token == "TK_EOS" then
  5883. return true
  5884. else
  5885. return false
  5886. end
  5887. end
  5888.  
  5889. ------------------------------------------------------------------------
  5890. -- parse a code block or unit
  5891. -- * used in multiple functions
  5892. ------------------------------------------------------------------------
  5893. function luaY:block(ls)
  5894. -- block -> chunk
  5895. local fs = ls.fs
  5896. local bl = {} -- BlockCnt
  5897. self:enterblock(fs, bl, false)
  5898. self:chunk(ls)
  5899. assert(bl.breaklist == luaK.NO_JUMP)
  5900. self:leaveblock(fs)
  5901. end
  5902.  
  5903. ------------------------------------------------------------------------
  5904. -- structure to chain all variables in the left-hand side of an
  5905. -- assignment
  5906. -- struct LHS_assign:
  5907. -- prev -- (table: struct LHS_assign)
  5908. -- v -- variable (global, local, upvalue, or indexed) (table: expdesc)
  5909. ------------------------------------------------------------------------
  5910.  
  5911. ------------------------------------------------------------------------
  5912. -- check whether, in an assignment to a local variable, the local variable
  5913. -- is needed in a previous assignment (to a table). If so, save original
  5914. -- local value in a safe place and use this safe copy in the previous
  5915. -- assignment.
  5916. -- * used in assignment()
  5917. ------------------------------------------------------------------------
  5918. function luaY:check_conflict(ls, lh, v)
  5919. local fs = ls.fs
  5920. local extra = fs.freereg -- eventual position to save local variable
  5921. local conflict = false
  5922. while lh do
  5923. if lh.v.k == "VINDEXED" then
  5924. if lh.v.info == v.info then -- conflict?
  5925. conflict = true
  5926. lh.v.info = extra -- previous assignment will use safe copy
  5927. end
  5928. if lh.v.aux == v.info then -- conflict?
  5929. conflict = true
  5930. lh.v.aux = extra -- previous assignment will use safe copy
  5931. end
  5932. end
  5933. lh = lh.prev
  5934. end
  5935. if conflict then
  5936. luaK:codeABC(fs, "OP_MOVE", fs.freereg, v.info, 0) -- make copy
  5937. luaK:reserveregs(fs, 1)
  5938. end
  5939. end
  5940.  
  5941. ------------------------------------------------------------------------
  5942. -- parse a variable assignment sequence
  5943. -- * recursively called
  5944. -- * used in exprstat()
  5945. ------------------------------------------------------------------------
  5946. function luaY:assignment(ls, lh, nvars)
  5947. local e = {} -- expdesc
  5948. -- test was: VLOCAL <= lh->v.k && lh->v.k <= VINDEXED
  5949. local c = lh.v.k
  5950. self:check_condition(ls, c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL"
  5951. or c == "VINDEXED", "syntax error")
  5952. if self:testnext(ls, ",") then -- assignment -> ',' primaryexp assignment
  5953. local nv = {} -- LHS_assign
  5954. nv.v = {}
  5955. nv.prev = lh
  5956. self:primaryexp(ls, nv.v)
  5957. if nv.v.k == "VLOCAL" then
  5958. self:check_conflict(ls, lh, nv.v)
  5959. end
  5960. self:checklimit(ls.fs, nvars, self.LUAI_MAXCCALLS - ls.L.nCcalls,
  5961. "variables in assignment")
  5962. self:assignment(ls, nv, nvars + 1)
  5963. else -- assignment -> '=' explist1
  5964. self:checknext(ls, "=")
  5965. local nexps = self:explist1(ls, e)
  5966. if nexps ~= nvars then
  5967. self:adjust_assign(ls, nvars, nexps, e)
  5968. if nexps > nvars then
  5969. ls.fs.freereg = ls.fs.freereg - (nexps - nvars) -- remove extra values
  5970. end
  5971. else
  5972. luaK:setoneret(ls.fs, e) -- close last expression
  5973. luaK:storevar(ls.fs, lh.v, e)
  5974. return -- avoid default
  5975. end
  5976. end
  5977. self:init_exp(e, "VNONRELOC", ls.fs.freereg - 1) -- default assignment
  5978. luaK:storevar(ls.fs, lh.v, e)
  5979. end
  5980.  
  5981. ------------------------------------------------------------------------
  5982. -- parse condition in a repeat statement or an if control structure
  5983. -- * used in repeatstat(), test_then_block()
  5984. ------------------------------------------------------------------------
  5985. function luaY:cond(ls)
  5986. -- cond -> exp
  5987. local v = {} -- expdesc
  5988. self:expr(ls, v) -- read condition
  5989. if v.k == "VNIL" then v.k = "VFALSE" end -- 'falses' are all equal here
  5990. luaK:goiftrue(ls.fs, v)
  5991. return v.f
  5992. end
  5993.  
  5994. ------------------------------------------------------------------------
  5995. -- parse a break statement
  5996. -- * used in statements()
  5997. ------------------------------------------------------------------------
  5998. function luaY:breakstat(ls)
  5999. -- stat -> BREAK
  6000. local fs = ls.fs
  6001. local bl = fs.bl
  6002. local upval = false
  6003. while bl and not bl.isbreakable do
  6004. if bl.upval then upval = true end
  6005. bl = bl.previous
  6006. end
  6007. if not bl then
  6008. luaX:syntaxerror(ls, "no loop to break")
  6009. end
  6010. if upval then
  6011. luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
  6012. end
  6013. bl.breaklist = luaK:concat(fs, bl.breaklist, luaK:jump(fs))
  6014. end
  6015.  
  6016. ------------------------------------------------------------------------
  6017. -- parse a while-do control structure, body processed by block()
  6018. -- * with dynamic array sizes, MAXEXPWHILE + EXTRAEXP limits imposed by
  6019. -- the function's implementation can be removed
  6020. -- * used in statements()
  6021. ------------------------------------------------------------------------
  6022. function luaY:whilestat(ls, line)
  6023. -- whilestat -> WHILE cond DO block END
  6024. local fs = ls.fs
  6025. local bl = {} -- BlockCnt
  6026. luaX:next(ls) -- skip WHILE
  6027. local whileinit = luaK:getlabel(fs)
  6028. local condexit = self:cond(ls)
  6029. self:enterblock(fs, bl, true)
  6030. self:checknext(ls, "TK_DO")
  6031. self:block(ls)
  6032. luaK:patchlist(fs, luaK:jump(fs), whileinit)
  6033. self:check_match(ls, "TK_END", "TK_WHILE", line)
  6034. self:leaveblock(fs)
  6035. luaK:patchtohere(fs, condexit) -- false conditions finish the loop
  6036. end
  6037.  
  6038. ------------------------------------------------------------------------
  6039. -- parse a repeat-until control structure, body parsed by chunk()
  6040. -- * used in statements()
  6041. ------------------------------------------------------------------------
  6042. function luaY:repeatstat(ls, line)
  6043. -- repeatstat -> REPEAT block UNTIL cond
  6044. local fs = ls.fs
  6045. local repeat_init = luaK:getlabel(fs)
  6046. local bl1, bl2 = {}, {} -- BlockCnt
  6047. self:enterblock(fs, bl1, true) -- loop block
  6048. self:enterblock(fs, bl2, false) -- scope block
  6049. luaX:next(ls) -- skip REPEAT
  6050. self:chunk(ls)
  6051. self:check_match(ls, "TK_UNTIL", "TK_REPEAT", line)
  6052. local condexit = self:cond(ls) -- read condition (inside scope block)
  6053. if not bl2.upval then -- no upvalues?
  6054. self:leaveblock(fs) -- finish scope
  6055. luaK:patchlist(ls.fs, condexit, repeat_init) -- close the loop
  6056. else -- complete semantics when there are upvalues
  6057. self:breakstat(ls) -- if condition then break
  6058. luaK:patchtohere(ls.fs, condexit) -- else...
  6059. self:leaveblock(fs) -- finish scope...
  6060. luaK:patchlist(ls.fs, luaK:jump(fs), repeat_init) -- and repeat
  6061. end
  6062. self:leaveblock(fs) -- finish loop
  6063. end
  6064.  
  6065. ------------------------------------------------------------------------
  6066. -- parse the single expressions needed in numerical for loops
  6067. -- * used in fornum()
  6068. ------------------------------------------------------------------------
  6069. function luaY:exp1(ls)
  6070. local e = {} -- expdesc
  6071. self:expr(ls, e)
  6072. local k = e.k
  6073. luaK:exp2nextreg(ls.fs, e)
  6074. return k
  6075. end
  6076.  
  6077. ------------------------------------------------------------------------
  6078. -- parse a for loop body for both versions of the for loop
  6079. -- * used in fornum(), forlist()
  6080. ------------------------------------------------------------------------
  6081. function luaY:forbody(ls, base, line, nvars, isnum)
  6082. -- forbody -> DO block
  6083. local bl = {} -- BlockCnt
  6084. local fs = ls.fs
  6085. self:adjustlocalvars(ls, 3) -- control variables
  6086. self:checknext(ls, "TK_DO")
  6087. local prep = isnum and luaK:codeAsBx(fs, "OP_FORPREP", base, luaK.NO_JUMP)
  6088. or luaK:jump(fs)
  6089. self:enterblock(fs, bl, false) -- scope for declared variables
  6090. self:adjustlocalvars(ls, nvars)
  6091. luaK:reserveregs(fs, nvars)
  6092. self:block(ls)
  6093. self:leaveblock(fs) -- end of scope for declared variables
  6094. luaK:patchtohere(fs, prep)
  6095. local endfor = isnum and luaK:codeAsBx(fs, "OP_FORLOOP", base, luaK.NO_JUMP)
  6096. or luaK:codeABC(fs, "OP_TFORLOOP", base, 0, nvars)
  6097. luaK:fixline(fs, line) -- pretend that `OP_FOR' starts the loop
  6098. luaK:patchlist(fs, isnum and endfor or luaK:jump(fs), prep + 1)
  6099. end
  6100.  
  6101. ------------------------------------------------------------------------
  6102. -- parse a numerical for loop, calls forbody()
  6103. -- * used in forstat()
  6104. ------------------------------------------------------------------------
  6105. function luaY:fornum(ls, varname, line)
  6106. -- fornum -> NAME = exp1,exp1[,exp1] forbody
  6107. local fs = ls.fs
  6108. local base = fs.freereg
  6109. self:new_localvarliteral(ls, "(for index)", 0)
  6110. self:new_localvarliteral(ls, "(for limit)", 1)
  6111. self:new_localvarliteral(ls, "(for step)", 2)
  6112. self:new_localvar(ls, varname, 3)
  6113. self:checknext(ls, '=')
  6114. self:exp1(ls) -- initial value
  6115. self:checknext(ls, ",")
  6116. self:exp1(ls) -- limit
  6117. if self:testnext(ls, ",") then
  6118. self:exp1(ls) -- optional step
  6119. else -- default step = 1
  6120. luaK:codeABx(fs, "OP_LOADK", fs.freereg, luaK:numberK(fs, 1))
  6121. luaK:reserveregs(fs, 1)
  6122. end
  6123. self:forbody(ls, base, line, 1, true)
  6124. end
  6125.  
  6126. ------------------------------------------------------------------------
  6127. -- parse a generic for loop, calls forbody()
  6128. -- * used in forstat()
  6129. ------------------------------------------------------------------------
  6130. function luaY:forlist(ls, indexname)
  6131. -- forlist -> NAME {,NAME} IN explist1 forbody
  6132. local fs = ls.fs
  6133. local e = {} -- expdesc
  6134. local nvars = 0
  6135. local base = fs.freereg
  6136. -- create control variables
  6137. self:new_localvarliteral(ls, "(for generator)", nvars)
  6138. nvars = nvars + 1
  6139. self:new_localvarliteral(ls, "(for state)", nvars)
  6140. nvars = nvars + 1
  6141. self:new_localvarliteral(ls, "(for control)", nvars)
  6142. nvars = nvars + 1
  6143. -- create declared variables
  6144. self:new_localvar(ls, indexname, nvars)
  6145. nvars = nvars + 1
  6146. while self:testnext(ls, ",") do
  6147. self:new_localvar(ls, self:str_checkname(ls), nvars)
  6148. nvars = nvars + 1
  6149. end
  6150. self:checknext(ls, "TK_IN")
  6151. local line = ls.linenumber
  6152. self:adjust_assign(ls, 3, self:explist1(ls, e), e)
  6153. luaK:checkstack(fs, 3) -- extra space to call generator
  6154. self:forbody(ls, base, line, nvars - 3, false)
  6155. end
  6156.  
  6157. ------------------------------------------------------------------------
  6158. -- initial parsing for a for loop, calls fornum() or forlist()
  6159. -- * used in statements()
  6160. ------------------------------------------------------------------------
  6161. function luaY:forstat(ls, line)
  6162. -- forstat -> FOR (fornum | forlist) END
  6163. local fs = ls.fs
  6164. local bl = {} -- BlockCnt
  6165. self:enterblock(fs, bl, true) -- scope for loop and control variables
  6166. luaX:next(ls) -- skip `for'
  6167. local varname = self:str_checkname(ls) -- first variable name
  6168. local c = ls.t.token
  6169. if c == "=" then
  6170. self:fornum(ls, varname, line)
  6171. elseif c == "," or c == "TK_IN" then
  6172. self:forlist(ls, varname)
  6173. else
  6174. luaX:syntaxerror(ls, self:LUA_QL("=").." or "..self:LUA_QL("in").." expected")
  6175. end
  6176. self:check_match(ls, "TK_END", "TK_FOR", line)
  6177. self:leaveblock(fs) -- loop scope (`break' jumps to this point)
  6178. end
  6179.  
  6180. ------------------------------------------------------------------------
  6181. -- parse part of an if control structure, including the condition
  6182. -- * used in ifstat()
  6183. ------------------------------------------------------------------------
  6184. function luaY:test_then_block(ls)
  6185. -- test_then_block -> [IF | ELSEIF] cond THEN block
  6186. luaX:next(ls) -- skip IF or ELSEIF
  6187. local condexit = self:cond(ls)
  6188. self:checknext(ls, "TK_THEN")
  6189. self:block(ls) -- `then' part
  6190. return condexit
  6191. end
  6192.  
  6193. ------------------------------------------------------------------------
  6194. -- parse an if control structure
  6195. -- * used in statements()
  6196. ------------------------------------------------------------------------
  6197. function luaY:ifstat(ls, line)
  6198. -- ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END
  6199. local fs = ls.fs
  6200. local escapelist = luaK.NO_JUMP
  6201. local flist = self:test_then_block(ls) -- IF cond THEN block
  6202. while ls.t.token == "TK_ELSEIF" do
  6203. escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
  6204. luaK:patchtohere(fs, flist)
  6205. flist = self:test_then_block(ls) -- ELSEIF cond THEN block
  6206. end
  6207. if ls.t.token == "TK_ELSE" then
  6208. escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
  6209. luaK:patchtohere(fs, flist)
  6210. luaX:next(ls) -- skip ELSE (after patch, for correct line info)
  6211. self:block(ls) -- 'else' part
  6212. else
  6213. escapelist = luaK:concat(fs, escapelist, flist)
  6214. end
  6215. luaK:patchtohere(fs, escapelist)
  6216. self:check_match(ls, "TK_END", "TK_IF", line)
  6217. end
  6218.  
  6219. ------------------------------------------------------------------------
  6220. -- parse a local function statement
  6221. -- * used in statements()
  6222. ------------------------------------------------------------------------
  6223. function luaY:localfunc(ls)
  6224. local v, b = {}, {} -- expdesc
  6225. local fs = ls.fs
  6226. self:new_localvar(ls, self:str_checkname(ls), 0)
  6227. self:init_exp(v, "VLOCAL", fs.freereg)
  6228. luaK:reserveregs(fs, 1)
  6229. self:adjustlocalvars(ls, 1)
  6230. self:body(ls, b, false, ls.linenumber)
  6231. luaK:storevar(fs, v, b)
  6232. -- debug information will only see the variable after this point!
  6233. self:getlocvar(fs, fs.nactvar - 1).startpc = fs.pc
  6234. end
  6235.  
  6236. ------------------------------------------------------------------------
  6237. -- parse a local variable declaration statement
  6238. -- * used in statements()
  6239. ------------------------------------------------------------------------
  6240. function luaY:localstat(ls)
  6241. -- stat -> LOCAL NAME {',' NAME} ['=' explist1]
  6242. local nvars = 0
  6243. local nexps
  6244. local e = {} -- expdesc
  6245. repeat
  6246. self:new_localvar(ls, self:str_checkname(ls), nvars)
  6247. nvars = nvars + 1
  6248. until not self:testnext(ls, ",")
  6249. if self:testnext(ls, "=") then
  6250. nexps = self:explist1(ls, e)
  6251. else
  6252. e.k = "VVOID"
  6253. nexps = 0
  6254. end
  6255. self:adjust_assign(ls, nvars, nexps, e)
  6256. self:adjustlocalvars(ls, nvars)
  6257. end
  6258.  
  6259. ------------------------------------------------------------------------
  6260. -- parse a function name specification
  6261. -- * used in funcstat()
  6262. ------------------------------------------------------------------------
  6263. function luaY:funcname(ls, v)
  6264. -- funcname -> NAME {field} [':' NAME]
  6265. local needself = false
  6266. self:singlevar(ls, v)
  6267. while ls.t.token == "." do
  6268. self:field(ls, v)
  6269. end
  6270. if ls.t.token == ":" then
  6271. needself = true
  6272. self:field(ls, v)
  6273. end
  6274. return needself
  6275. end
  6276.  
  6277. ------------------------------------------------------------------------
  6278. -- parse a function statement
  6279. -- * used in statements()
  6280. ------------------------------------------------------------------------
  6281. function luaY:funcstat(ls, line)
  6282. -- funcstat -> FUNCTION funcname body
  6283. local v, b = {}, {} -- expdesc
  6284. luaX:next(ls) -- skip FUNCTION
  6285. local needself = self:funcname(ls, v)
  6286. self:body(ls, b, needself, line)
  6287. luaK:storevar(ls.fs, v, b)
  6288. luaK:fixline(ls.fs, line) -- definition 'happens' in the first line
  6289. end
  6290.  
  6291. ------------------------------------------------------------------------
  6292. -- parse a function call with no returns or an assignment statement
  6293. -- * used in statements()
  6294. ------------------------------------------------------------------------
  6295. function luaY:exprstat(ls)
  6296. -- stat -> func | assignment
  6297. local fs = ls.fs
  6298. local v = {} -- LHS_assign
  6299. v.v = {}
  6300. self:primaryexp(ls, v.v)
  6301. if v.v.k == "VCALL" then -- stat -> func
  6302. luaP:SETARG_C(luaK:getcode(fs, v.v), 1) -- call statement uses no results
  6303. else -- stat -> assignment
  6304. v.prev = nil
  6305. self:assignment(ls, v, 1)
  6306. end
  6307. end
  6308.  
  6309. ------------------------------------------------------------------------
  6310. -- parse a return statement
  6311. -- * used in statements()
  6312. ------------------------------------------------------------------------
  6313. function luaY:retstat(ls)
  6314. -- stat -> RETURN explist
  6315. local fs = ls.fs
  6316. local e = {} -- expdesc
  6317. local first, nret -- registers with returned values
  6318. luaX:next(ls) -- skip RETURN
  6319. if self:block_follow(ls.t.token) or ls.t.token == ";" then
  6320. first, nret = 0, 0 -- return no values
  6321. else
  6322. nret = self:explist1(ls, e) -- optional return values
  6323. if self:hasmultret(e.k) then
  6324. luaK:setmultret(fs, e)
  6325. if e.k == "VCALL" and nret == 1 then -- tail call?
  6326. luaP:SET_OPCODE(luaK:getcode(fs, e), "OP_TAILCALL")
  6327. assert(luaP:GETARG_A(luaK:getcode(fs, e)) == fs.nactvar)
  6328. end
  6329. first = fs.nactvar
  6330. nret = self.LUA_MULTRET -- return all values
  6331. else
  6332. if nret == 1 then -- only one single value?
  6333. first = luaK:exp2anyreg(fs, e)
  6334. else
  6335. luaK:exp2nextreg(fs, e) -- values must go to the 'stack'
  6336. first = fs.nactvar -- return all 'active' values
  6337. assert(nret == fs.freereg - first)
  6338. end
  6339. end--if
  6340. end--if
  6341. luaK:ret(fs, first, nret)
  6342. end
  6343.  
  6344. ------------------------------------------------------------------------
  6345. -- initial parsing for statements, calls a lot of functions
  6346. -- * returns boolean instead of 0|1
  6347. -- * used in chunk()
  6348. ------------------------------------------------------------------------
  6349. function luaY:statement(ls)
  6350. local line = ls.linenumber -- may be needed for error messages
  6351. local c = ls.t.token
  6352. if c == "TK_IF" then -- stat -> ifstat
  6353. self:ifstat(ls, line)
  6354. return false
  6355. elseif c == "TK_WHILE" then -- stat -> whilestat
  6356. self:whilestat(ls, line)
  6357. return false
  6358. elseif c == "TK_DO" then -- stat -> DO block END
  6359. luaX:next(ls) -- skip DO
  6360. self:block(ls)
  6361. self:check_match(ls, "TK_END", "TK_DO", line)
  6362. return false
  6363. elseif c == "TK_FOR" then -- stat -> forstat
  6364. self:forstat(ls, line)
  6365. return false
  6366. elseif c == "TK_REPEAT" then -- stat -> repeatstat
  6367. self:repeatstat(ls, line)
  6368. return false
  6369. elseif c == "TK_FUNCTION" then -- stat -> funcstat
  6370. self:funcstat(ls, line)
  6371. return false
  6372. elseif c == "TK_LOCAL" then -- stat -> localstat
  6373. luaX:next(ls) -- skip LOCAL
  6374. if self:testnext(ls, "TK_FUNCTION") then -- local function?
  6375. self:localfunc(ls)
  6376. else
  6377. self:localstat(ls)
  6378. end
  6379. return false
  6380. elseif c == "TK_RETURN" then -- stat -> retstat
  6381. self:retstat(ls)
  6382. return true -- must be last statement
  6383. elseif c == "TK_BREAK" then -- stat -> breakstat
  6384. luaX:next(ls) -- skip BREAK
  6385. self:breakstat(ls)
  6386. return true -- must be last statement
  6387. else
  6388. self:exprstat(ls)
  6389. return false -- to avoid warnings
  6390. end--if c
  6391. end
  6392.  
  6393. ------------------------------------------------------------------------
  6394. -- parse a chunk, which consists of a bunch of statements
  6395. -- * used in parser(), body(), block(), repeatstat()
  6396. ------------------------------------------------------------------------
  6397. function luaY:chunk(ls)
  6398. -- chunk -> { stat [';'] }
  6399. local islast = false
  6400. self:enterlevel(ls)
  6401. while not islast and not self:block_follow(ls.t.token) do
  6402. islast = self:statement(ls)
  6403. self:testnext(ls, ";")
  6404. assert(ls.fs.f.maxstacksize >= ls.fs.freereg and
  6405. ls.fs.freereg >= ls.fs.nactvar)
  6406. ls.fs.freereg = ls.fs.nactvar -- free registers
  6407. end
  6408. self:leavelevel(ls)
  6409. end
  6410.  
  6411. -- }======================================================================
  6412. return luaY]]></ProtectedString>
  6413. <BinaryString name="Tags"></BinaryString>
  6414. </Properties>
  6415. </Item>
  6416. <Item class="ModuleScript" referent="RBX6D281683B751445CAD6CA6A9CAA1B31F">
  6417. <Properties>
  6418. <Content name="LinkedSource"><null></null></Content>
  6419. <string name="Name">LuaK</string>
  6420. <string name="ScriptGuid">{E74CCBE8-6F78-46F4-B517-8E4B60989D32}</string>
  6421. <ProtectedString name="Source"><![CDATA[--[[--------------------------------------------------------------------
  6422.  
  6423. lcode.lua
  6424. Lua 5 code generator in Lua
  6425. This file is part of Yueliang.
  6426.  
  6427. Copyright (c) 2005-2007 Kein-Hong Man <[email protected]>
  6428. The COPYRIGHT file describes the conditions
  6429. under which this software may be distributed.
  6430.  
  6431. See the ChangeLog for more information.
  6432.  
  6433. ----------------------------------------------------------------------]]
  6434.  
  6435. --[[--------------------------------------------------------------------
  6436. -- Notes:
  6437. -- * one function manipulate a pointer argument with a simple data type
  6438. -- (can't be emulated by a table, ambiguous), now returns that value:
  6439. -- luaK:concat(fs, l1, l2)
  6440. -- * luaM_growvector uses the faux luaY:growvector, for limit checking
  6441. -- * some function parameters changed to boolean, additional code
  6442. -- translates boolean back to 1/0 for instruction fields
  6443. --
  6444. -- Not implemented:
  6445. -- * NOTE there is a failed assert in luaK:addk, a porting problem
  6446. --
  6447. -- Added:
  6448. -- * constant MAXSTACK from llimits.h
  6449. -- * luaK:ttisnumber(o) (from lobject.h)
  6450. -- * luaK:nvalue(o) (from lobject.h)
  6451. -- * luaK:setnilvalue(o) (from lobject.h)
  6452. -- * luaK:setnvalue(o, x) (from lobject.h)
  6453. -- * luaK:setbvalue(o, x) (from lobject.h)
  6454. -- * luaK:sethvalue(o, x) (from lobject.h), parameter L deleted
  6455. -- * luaK:setsvalue(o, x) (from lobject.h), parameter L deleted
  6456. -- * luaK:numadd, luaK:numsub, luaK:nummul, luaK:numdiv, luaK:nummod,
  6457. -- luaK:numpow, luaK:numunm, luaK:numisnan (from luaconf.h)
  6458. -- * copyexp(e1, e2) added in luaK:posfix to copy expdesc struct
  6459. --
  6460. -- Changed in 5.1.x:
  6461. -- * enum BinOpr has a new entry, OPR_MOD
  6462. -- * enum UnOpr has a new entry, OPR_LEN
  6463. -- * binopistest, unused in 5.0.x, has been deleted
  6464. -- * macro setmultret is new
  6465. -- * functions isnumeral, luaK_ret, boolK are new
  6466. -- * funcion nilK was named nil_constant in 5.0.x
  6467. -- * function interface changed: need_value, patchtestreg, concat
  6468. -- * TObject now a TValue
  6469. -- * functions luaK_setreturns, luaK_setoneret are new
  6470. -- * function luaK:setcallreturns deleted, to be replaced by:
  6471. -- luaK:setmultret, luaK:ret, luaK:setreturns, luaK:setoneret
  6472. -- * functions constfolding, codearith, codecomp are new
  6473. -- * luaK:codebinop has been deleted
  6474. -- * function luaK_setlist is new
  6475. -- * OPR_MULT renamed to OPR_MUL
  6476. ----------------------------------------------------------------------]]
  6477.  
  6478. -- requires luaP, luaX, luaY
  6479. local luaK = {}
  6480. local luaP = require(script.Parent.LuaP)
  6481. local luaX = require(script.Parent.LuaX)
  6482.  
  6483. ------------------------------------------------------------------------
  6484. -- constants used by code generator
  6485. ------------------------------------------------------------------------
  6486. -- maximum stack for a Lua function
  6487. luaK.MAXSTACK = 250 -- (from llimits.h)
  6488.  
  6489. --[[--------------------------------------------------------------------
  6490. -- other functions
  6491. ----------------------------------------------------------------------]]
  6492.  
  6493. ------------------------------------------------------------------------
  6494. -- emulation of TValue macros (these are from lobject.h)
  6495. -- * TValue is a table since lcode passes references around
  6496. -- * tt member field removed, using Lua's type() instead
  6497. -- * for setsvalue, sethvalue, parameter L (deleted here) in lobject.h
  6498. -- is used in an assert for testing, see checkliveness(g,obj)
  6499. ------------------------------------------------------------------------
  6500. function luaK:ttisnumber(o)
  6501. if o then return type(o.value) == "number" else return false end
  6502. end
  6503. function luaK:nvalue(o) return o.value end
  6504. function luaK:setnilvalue(o) o.value = nil end
  6505. function luaK:setsvalue(o, x) o.value = x end
  6506. luaK.setnvalue = luaK.setsvalue
  6507. luaK.sethvalue = luaK.setsvalue
  6508. luaK.setbvalue = luaK.setsvalue
  6509.  
  6510. ------------------------------------------------------------------------
  6511. -- The luai_num* macros define the primitive operations over numbers.
  6512. -- * this is not the entire set of primitive operations from luaconf.h
  6513. -- * used in luaK:constfolding()
  6514. ------------------------------------------------------------------------
  6515. function luaK:numadd(a, b) return a + b end
  6516. function luaK:numsub(a, b) return a - b end
  6517. function luaK:nummul(a, b) return a * b end
  6518. function luaK:numdiv(a, b) return a / b end
  6519. function luaK:nummod(a, b) return a % b end
  6520. -- ((a) - floor((a)/(b))*(b)) /* actual, for reference */
  6521. function luaK:numpow(a, b) return a ^ b end
  6522. function luaK:numunm(a) return -a end
  6523. function luaK:numisnan(a) return not a == a end
  6524. -- a NaN cannot equal another NaN
  6525.  
  6526. --[[--------------------------------------------------------------------
  6527. -- code generator functions
  6528. ----------------------------------------------------------------------]]
  6529.  
  6530. ------------------------------------------------------------------------
  6531. -- Marks the end of a patch list. It is an invalid value both as an absolute
  6532. -- address, and as a list link (would link an element to itself).
  6533. ------------------------------------------------------------------------
  6534. luaK.NO_JUMP = -1
  6535.  
  6536. ------------------------------------------------------------------------
  6537. -- grep "ORDER OPR" if you change these enums
  6538. ------------------------------------------------------------------------
  6539. luaK.BinOpr = {
  6540. OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5,
  6541. OPR_CONCAT = 6,
  6542. OPR_NE = 7, OPR_EQ = 8,
  6543. OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12,
  6544. OPR_AND = 13, OPR_OR = 14,
  6545. OPR_NOBINOPR = 15,
  6546. }
  6547.  
  6548. -- * UnOpr is used by luaK:prefix's op argument, but not directly used
  6549. -- because the function receives the symbols as strings, e.g. "OPR_NOT"
  6550. luaK.UnOpr = {
  6551. OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3
  6552. }
  6553.  
  6554. ------------------------------------------------------------------------
  6555. -- returns the instruction object for given e (expdesc), was a macro
  6556. ------------------------------------------------------------------------
  6557. function luaK:getcode(fs, e)
  6558. return fs.f.code[e.info]
  6559. end
  6560.  
  6561. ------------------------------------------------------------------------
  6562. -- codes an instruction with a signed Bx (sBx) field, was a macro
  6563. -- * used in luaK:jump(), (lparser) luaY:forbody()
  6564. ------------------------------------------------------------------------
  6565. function luaK:codeAsBx(fs, o, A, sBx)
  6566. return self:codeABx(fs, o, A, sBx + luaP.MAXARG_sBx)
  6567. end
  6568.  
  6569. ------------------------------------------------------------------------
  6570. -- set the expdesc e instruction for multiple returns, was a macro
  6571. ------------------------------------------------------------------------
  6572. function luaK:setmultret(fs, e)
  6573. self:setreturns(fs, e, luaY.LUA_MULTRET)
  6574. end
  6575.  
  6576. ------------------------------------------------------------------------
  6577. -- there is a jump if patch lists are not identical, was a macro
  6578. -- * used in luaK:exp2reg(), luaK:exp2anyreg(), luaK:exp2val()
  6579. ------------------------------------------------------------------------
  6580. function luaK:hasjumps(e)
  6581. return e.t ~= e.f
  6582. end
  6583.  
  6584. ------------------------------------------------------------------------
  6585. -- true if the expression is a constant number (for constant folding)
  6586. -- * used in constfolding(), infix()
  6587. ------------------------------------------------------------------------
  6588. function luaK:isnumeral(e)
  6589. return e.k == "VKNUM" and e.t == self.NO_JUMP and e.f == self.NO_JUMP
  6590. end
  6591.  
  6592. ------------------------------------------------------------------------
  6593. -- codes loading of nil, optimization done if consecutive locations
  6594. -- * used in luaK:discharge2reg(), (lparser) luaY:adjust_assign()
  6595. ------------------------------------------------------------------------
  6596. function luaK:_nil(fs, from, n)
  6597. if fs.pc > fs.lasttarget then -- no jumps to current position?
  6598. if fs.pc == 0 then -- function start?
  6599. if from >= fs.nactvar then
  6600. return -- positions are already clean
  6601. end
  6602. else
  6603. local previous = fs.f.code[fs.pc - 1]
  6604. if luaP:GET_OPCODE(previous) == "OP_LOADNIL" then
  6605. local pfrom = luaP:GETARG_A(previous)
  6606. local pto = luaP:GETARG_B(previous)
  6607. if pfrom <= from and from <= pto + 1 then -- can connect both?
  6608. if from + n - 1 > pto then
  6609. luaP:SETARG_B(previous, from + n - 1)
  6610. end
  6611. return
  6612. end
  6613. end
  6614. end
  6615. end
  6616. self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0) -- else no optimization
  6617. end
  6618.  
  6619. ------------------------------------------------------------------------
  6620. --
  6621. -- * used in multiple locations
  6622. ------------------------------------------------------------------------
  6623. function luaK:jump(fs)
  6624. local jpc = fs.jpc -- save list of jumps to here
  6625. fs.jpc = self.NO_JUMP
  6626. local j = self:codeAsBx(fs, "OP_JMP", 0, self.NO_JUMP)
  6627. j = self:concat(fs, j, jpc) -- keep them on hold
  6628. return j
  6629. end
  6630.  
  6631. ------------------------------------------------------------------------
  6632. -- codes a RETURN instruction
  6633. -- * used in luaY:close_func(), luaY:retstat()
  6634. ------------------------------------------------------------------------
  6635. function luaK:ret(fs, first, nret)
  6636. self:codeABC(fs, "OP_RETURN", first, nret + 1, 0)
  6637. end
  6638.  
  6639. ------------------------------------------------------------------------
  6640. --
  6641. -- * used in luaK:jumponcond(), luaK:codecomp()
  6642. ------------------------------------------------------------------------
  6643. function luaK:condjump(fs, op, A, B, C)
  6644. self:codeABC(fs, op, A, B, C)
  6645. return self:jump(fs)
  6646. end
  6647.  
  6648. ------------------------------------------------------------------------
  6649. --
  6650. -- * used in luaK:patchlistaux(), luaK:concat()
  6651. ------------------------------------------------------------------------
  6652. function luaK:fixjump(fs, pc, dest)
  6653. local jmp = fs.f.code[pc]
  6654. local offset = dest - (pc + 1)
  6655. assert(dest ~= self.NO_JUMP)
  6656. if math.abs(offset) > luaP.MAXARG_sBx then
  6657. luaX:syntaxerror(fs.ls, "control structure too long")
  6658. end
  6659. luaP:SETARG_sBx(jmp, offset)
  6660. end
  6661.  
  6662. ------------------------------------------------------------------------
  6663. -- returns current 'pc' and marks it as a jump target (to avoid wrong
  6664. -- optimizations with consecutive instructions not in the same basic block).
  6665. -- * used in multiple locations
  6666. -- * fs.lasttarget tested only by luaK:_nil() when optimizing OP_LOADNIL
  6667. ------------------------------------------------------------------------
  6668. function luaK:getlabel(fs)
  6669. fs.lasttarget = fs.pc
  6670. return fs.pc
  6671. end
  6672.  
  6673. ------------------------------------------------------------------------
  6674. --
  6675. -- * used in luaK:need_value(), luaK:removevalues(), luaK:patchlistaux(),
  6676. -- luaK:concat()
  6677. ------------------------------------------------------------------------
  6678. function luaK:getjump(fs, pc)
  6679. local offset = luaP:GETARG_sBx(fs.f.code[pc])
  6680. if offset == self.NO_JUMP then -- point to itself represents end of list
  6681. return self.NO_JUMP -- end of list
  6682. else
  6683. return (pc + 1) + offset -- turn offset into absolute position
  6684. end
  6685. end
  6686.  
  6687. ------------------------------------------------------------------------
  6688. --
  6689. -- * used in luaK:need_value(), luaK:patchtestreg(), luaK:invertjump()
  6690. ------------------------------------------------------------------------
  6691. function luaK:getjumpcontrol(fs, pc)
  6692. local pi = fs.f.code[pc]
  6693. local ppi = fs.f.code[pc - 1]
  6694. if pc >= 1 and luaP:testTMode(luaP:GET_OPCODE(ppi)) ~= 0 then
  6695. return ppi
  6696. else
  6697. return pi
  6698. end
  6699. end
  6700.  
  6701. ------------------------------------------------------------------------
  6702. -- check whether list has any jump that do not produce a value
  6703. -- (or produce an inverted value)
  6704. -- * return value changed to boolean
  6705. -- * used only in luaK:exp2reg()
  6706. ------------------------------------------------------------------------
  6707. function luaK:need_value(fs, list)
  6708. while list ~= self.NO_JUMP do
  6709. local i = self:getjumpcontrol(fs, list)
  6710. if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then return true end
  6711. list = self:getjump(fs, list)
  6712. end
  6713. return false -- not found
  6714. end
  6715.  
  6716. ------------------------------------------------------------------------
  6717. --
  6718. -- * used in luaK:removevalues(), luaK:patchlistaux()
  6719. ------------------------------------------------------------------------
  6720. function luaK:patchtestreg(fs, node, reg)
  6721. local i = self:getjumpcontrol(fs, node)
  6722. if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then
  6723. return false -- cannot patch other instructions
  6724. end
  6725. if reg ~= luaP.NO_REG and reg ~= luaP:GETARG_B(i) then
  6726. luaP:SETARG_A(i, reg)
  6727. else -- no register to put value or register already has the value
  6728. -- due to use of a table as i, i cannot be replaced by another table
  6729. -- so the following is required; there is no change to ARG_C
  6730. luaP:SET_OPCODE(i, "OP_TEST")
  6731. local b = luaP:GETARG_B(i)
  6732. luaP:SETARG_A(i, b)
  6733. luaP:SETARG_B(i, 0)
  6734. -- *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); /* C */
  6735. end
  6736. return true
  6737. end
  6738.  
  6739. ------------------------------------------------------------------------
  6740. --
  6741. -- * used only in luaK:codenot()
  6742. ------------------------------------------------------------------------
  6743. function luaK:removevalues(fs, list)
  6744. while list ~= self.NO_JUMP do
  6745. self:patchtestreg(fs, list, luaP.NO_REG)
  6746. list = self:getjump(fs, list)
  6747. end
  6748. end
  6749.  
  6750. ------------------------------------------------------------------------
  6751. --
  6752. -- * used in luaK:dischargejpc(), luaK:patchlist(), luaK:exp2reg()
  6753. ------------------------------------------------------------------------
  6754. function luaK:patchlistaux(fs, list, vtarget, reg, dtarget)
  6755. while list ~= self.NO_JUMP do
  6756. local _next = self:getjump(fs, list)
  6757. if self:patchtestreg(fs, list, reg) then
  6758. self:fixjump(fs, list, vtarget)
  6759. else
  6760. self:fixjump(fs, list, dtarget) -- jump to default target
  6761. end
  6762. list = _next
  6763. end
  6764. end
  6765.  
  6766. ------------------------------------------------------------------------
  6767. --
  6768. -- * used only in luaK:code()
  6769. ------------------------------------------------------------------------
  6770. function luaK:dischargejpc(fs)
  6771. self:patchlistaux(fs, fs.jpc, fs.pc, luaP.NO_REG, fs.pc)
  6772. fs.jpc = self.NO_JUMP
  6773. end
  6774.  
  6775. ------------------------------------------------------------------------
  6776. --
  6777. -- * used in (lparser) luaY:whilestat(), luaY:repeatstat(), luaY:forbody()
  6778. ------------------------------------------------------------------------
  6779. function luaK:patchlist(fs, list, target)
  6780. if target == fs.pc then
  6781. self:patchtohere(fs, list)
  6782. else
  6783. assert(target < fs.pc)
  6784. self:patchlistaux(fs, list, target, luaP.NO_REG, target)
  6785. end
  6786. end
  6787.  
  6788. ------------------------------------------------------------------------
  6789. --
  6790. -- * used in multiple locations
  6791. ------------------------------------------------------------------------
  6792. function luaK:patchtohere(fs, list)
  6793. self:getlabel(fs)
  6794. fs.jpc = self:concat(fs, fs.jpc, list)
  6795. end
  6796.  
  6797. ------------------------------------------------------------------------
  6798. -- * l1 was a pointer, now l1 is returned and callee assigns the value
  6799. -- * used in multiple locations
  6800. ------------------------------------------------------------------------
  6801. function luaK:concat(fs, l1, l2)
  6802. if l2 == self.NO_JUMP then return l1
  6803. elseif l1 == self.NO_JUMP then
  6804. return l2
  6805. else
  6806. local list = l1
  6807. local _next = self:getjump(fs, list)
  6808. while _next ~= self.NO_JUMP do -- find last element
  6809. list = _next
  6810. _next = self:getjump(fs, list)
  6811. end
  6812. self:fixjump(fs, list, l2)
  6813. end
  6814. return l1
  6815. end
  6816.  
  6817. ------------------------------------------------------------------------
  6818. --
  6819. -- * used in luaK:reserveregs(), (lparser) luaY:forlist()
  6820. ------------------------------------------------------------------------
  6821. function luaK:checkstack(fs, n)
  6822. local newstack = fs.freereg + n
  6823. if newstack > fs.f.maxstacksize then
  6824. if newstack >= self.MAXSTACK then
  6825. luaX:syntaxerror(fs.ls, "function or expression too complex")
  6826. end
  6827. fs.f.maxstacksize = newstack
  6828. end
  6829. end
  6830.  
  6831. ------------------------------------------------------------------------
  6832. --
  6833. -- * used in multiple locations
  6834. ------------------------------------------------------------------------
  6835. function luaK:reserveregs(fs, n)
  6836. self:checkstack(fs, n)
  6837. fs.freereg = fs.freereg + n
  6838. end
  6839.  
  6840. ------------------------------------------------------------------------
  6841. --
  6842. -- * used in luaK:freeexp(), luaK:dischargevars()
  6843. ------------------------------------------------------------------------
  6844. function luaK:freereg(fs, reg)
  6845. if not luaP:ISK(reg) and reg >= fs.nactvar then
  6846. fs.freereg = fs.freereg - 1
  6847. assert(reg == fs.freereg)
  6848. end
  6849. end
  6850.  
  6851. ------------------------------------------------------------------------
  6852. --
  6853. -- * used in multiple locations
  6854. ------------------------------------------------------------------------
  6855. function luaK:freeexp(fs, e)
  6856. if e.k == "VNONRELOC" then
  6857. self:freereg(fs, e.info)
  6858. end
  6859. end
  6860.  
  6861. ------------------------------------------------------------------------
  6862. -- * TODO NOTE implementation is not 100% correct, since the assert fails
  6863. -- * luaH_set, setobj deleted; direct table access used instead
  6864. -- * used in luaK:stringK(), luaK:numberK(), luaK:boolK(), luaK:nilK()
  6865. ------------------------------------------------------------------------
  6866. function luaK:addk(fs, k, v)
  6867. local L = fs.L
  6868. local idx = fs.h[k.value]
  6869. --TValue *idx = luaH_set(L, fs->h, k); /* C */
  6870. local f = fs.f
  6871. if self:ttisnumber(idx) then
  6872. --TODO this assert currently FAILS (last tested for 5.0.2)
  6873. --assert(fs.f.k[self:nvalue(idx)] == v)
  6874. --assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); /* C */
  6875. return self:nvalue(idx)
  6876. else -- constant not found; create a new entry
  6877. idx = {}
  6878. self:setnvalue(idx, fs.nk)
  6879. fs.h[k.value] = idx
  6880. -- setnvalue(idx, cast_num(fs->nk)); /* C */
  6881. luaY:growvector(L, f.k, fs.nk, f.sizek, nil,
  6882. luaP.MAXARG_Bx, "constant table overflow")
  6883. -- loop to initialize empty f.k positions not required
  6884. f.k[fs.nk] = v
  6885. -- setobj(L, &f->k[fs->nk], v); /* C */
  6886. -- luaC_barrier(L, f, v); /* GC */
  6887. local nk = fs.nk
  6888. fs.nk = fs.nk + 1
  6889. return nk
  6890. end
  6891.  
  6892. end
  6893.  
  6894. ------------------------------------------------------------------------
  6895. -- creates and sets a string object
  6896. -- * used in (lparser) luaY:codestring(), luaY:singlevar()
  6897. ------------------------------------------------------------------------
  6898. function luaK:stringK(fs, s)
  6899. local o = {} -- TValue
  6900. self:setsvalue(o, s)
  6901. return self:addk(fs, o, o)
  6902. end
  6903.  
  6904. ------------------------------------------------------------------------
  6905. -- creates and sets a number object
  6906. -- * used in luaK:prefix() for negative (or negation of) numbers
  6907. -- * used in (lparser) luaY:simpleexp(), luaY:fornum()
  6908. ------------------------------------------------------------------------
  6909. function luaK:numberK(fs, r)
  6910. local o = {} -- TValue
  6911. self:setnvalue(o, r)
  6912. return self:addk(fs, o, o)
  6913. end
  6914.  
  6915. ------------------------------------------------------------------------
  6916. -- creates and sets a boolean object
  6917. -- * used only in luaK:exp2RK()
  6918. ------------------------------------------------------------------------
  6919. function luaK:boolK(fs, b)
  6920. local o = {} -- TValue
  6921. self:setbvalue(o, b)
  6922. return self:addk(fs, o, o)
  6923. end
  6924.  
  6925. ------------------------------------------------------------------------
  6926. -- creates and sets a nil object
  6927. -- * used only in luaK:exp2RK()
  6928. ------------------------------------------------------------------------
  6929. function luaK:nilK(fs)
  6930. local k, v = {}, {} -- TValue
  6931. self:setnilvalue(v)
  6932. -- cannot use nil as key; instead use table itself to represent nil
  6933. self:sethvalue(k, fs.h)
  6934. return self:addk(fs, k, v)
  6935. end
  6936.  
  6937. ------------------------------------------------------------------------
  6938. --
  6939. -- * used in luaK:setmultret(), (lparser) luaY:adjust_assign()
  6940. ------------------------------------------------------------------------
  6941. function luaK:setreturns(fs, e, nresults)
  6942. if e.k == "VCALL" then -- expression is an open function call?
  6943. luaP:SETARG_C(self:getcode(fs, e), nresults + 1)
  6944. elseif e.k == "VVARARG" then
  6945. luaP:SETARG_B(self:getcode(fs, e), nresults + 1);
  6946. luaP:SETARG_A(self:getcode(fs, e), fs.freereg);
  6947. luaK:reserveregs(fs, 1)
  6948. end
  6949. end
  6950.  
  6951. ------------------------------------------------------------------------
  6952. --
  6953. -- * used in luaK:dischargevars(), (lparser) luaY:assignment()
  6954. ------------------------------------------------------------------------
  6955. function luaK:setoneret(fs, e)
  6956. if e.k == "VCALL" then -- expression is an open function call?
  6957. e.k = "VNONRELOC"
  6958. e.info = luaP:GETARG_A(self:getcode(fs, e))
  6959. elseif e.k == "VVARARG" then
  6960. luaP:SETARG_B(self:getcode(fs, e), 2)
  6961. e.k = "VRELOCABLE" -- can relocate its simple result
  6962. end
  6963. end
  6964.  
  6965. ------------------------------------------------------------------------
  6966. --
  6967. -- * used in multiple locations
  6968. ------------------------------------------------------------------------
  6969. function luaK:dischargevars(fs, e)
  6970. local k = e.k
  6971. if k == "VLOCAL" then
  6972. e.k = "VNONRELOC"
  6973. elseif k == "VUPVAL" then
  6974. e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0)
  6975. e.k = "VRELOCABLE"
  6976. elseif k == "VGLOBAL" then
  6977. e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info)
  6978. e.k = "VRELOCABLE"
  6979. elseif k == "VINDEXED" then
  6980. self:freereg(fs, e.aux)
  6981. self:freereg(fs, e.info)
  6982. e.info = self:codeABC(fs, "OP_GETTABLE", 0, e.info, e.aux)
  6983. e.k = "VRELOCABLE"
  6984. elseif k == "VVARARG" or k == "VCALL" then
  6985. self:setoneret(fs, e)
  6986. else
  6987. -- there is one value available (somewhere)
  6988. end
  6989. end
  6990.  
  6991. ------------------------------------------------------------------------
  6992. --
  6993. -- * used only in luaK:exp2reg()
  6994. ------------------------------------------------------------------------
  6995. function luaK:code_label(fs, A, b, jump)
  6996. self:getlabel(fs) -- those instructions may be jump targets
  6997. return self:codeABC(fs, "OP_LOADBOOL", A, b, jump)
  6998. end
  6999.  
  7000. ------------------------------------------------------------------------
  7001. --
  7002. -- * used in luaK:discharge2anyreg(), luaK:exp2reg()
  7003. ------------------------------------------------------------------------
  7004. function luaK:discharge2reg(fs, e, reg)
  7005. self:dischargevars(fs, e)
  7006. local k = e.k
  7007. if k == "VNIL" then
  7008. self:_nil(fs, reg, 1)
  7009. elseif k == "VFALSE" or k == "VTRUE" then
  7010. self:codeABC(fs, "OP_LOADBOOL", reg, (e.k == "VTRUE") and 1 or 0, 0)
  7011. elseif k == "VK" then
  7012. self:codeABx(fs, "OP_LOADK", reg, e.info)
  7013. elseif k == "VKNUM" then
  7014. self:codeABx(fs, "OP_LOADK", reg, self:numberK(fs, e.nval))
  7015. elseif k == "VRELOCABLE" then
  7016. local pc = self:getcode(fs, e)
  7017. luaP:SETARG_A(pc, reg)
  7018. elseif k == "VNONRELOC" then
  7019. if reg ~= e.info then
  7020. self:codeABC(fs, "OP_MOVE", reg, e.info, 0)
  7021. end
  7022. else
  7023. assert(e.k == "VVOID" or e.k == "VJMP")
  7024. return -- nothing to do...
  7025. end
  7026. e.info = reg
  7027. e.k = "VNONRELOC"
  7028. end
  7029.  
  7030. ------------------------------------------------------------------------
  7031. --
  7032. -- * used in luaK:jumponcond(), luaK:codenot()
  7033. ------------------------------------------------------------------------
  7034. function luaK:discharge2anyreg(fs, e)
  7035. if e.k ~= "VNONRELOC" then
  7036. self:reserveregs(fs, 1)
  7037. self:discharge2reg(fs, e, fs.freereg - 1)
  7038. end
  7039. end
  7040.  
  7041. ------------------------------------------------------------------------
  7042. --
  7043. -- * used in luaK:exp2nextreg(), luaK:exp2anyreg(), luaK:storevar()
  7044. ------------------------------------------------------------------------
  7045. function luaK:exp2reg(fs, e, reg)
  7046. self:discharge2reg(fs, e, reg)
  7047. if e.k == "VJMP" then
  7048. e.t = self:concat(fs, e.t, e.info) -- put this jump in 't' list
  7049. end
  7050. if self:hasjumps(e) then
  7051. local final -- position after whole expression
  7052. local p_f = self.NO_JUMP -- position of an eventual LOAD false
  7053. local p_t = self.NO_JUMP -- position of an eventual LOAD true
  7054. if self:need_value(fs, e.t) or self:need_value(fs, e.f) then
  7055. local fj = (e.k == "VJMP") and self.NO_JUMP or self:jump(fs)
  7056. p_f = self:code_label(fs, reg, 0, 1)
  7057. p_t = self:code_label(fs, reg, 1, 0)
  7058. self:patchtohere(fs, fj)
  7059. end
  7060. final = self:getlabel(fs)
  7061. self:patchlistaux(fs, e.f, final, reg, p_f)
  7062. self:patchlistaux(fs, e.t, final, reg, p_t)
  7063. end
  7064. e.f, e.t = self.NO_JUMP, self.NO_JUMP
  7065. e.info = reg
  7066. e.k = "VNONRELOC"
  7067. end
  7068.  
  7069. ------------------------------------------------------------------------
  7070. --
  7071. -- * used in multiple locations
  7072. ------------------------------------------------------------------------
  7073. function luaK:exp2nextreg(fs, e)
  7074. self:dischargevars(fs, e)
  7075. self:freeexp(fs, e)
  7076. self:reserveregs(fs, 1)
  7077. self:exp2reg(fs, e, fs.freereg - 1)
  7078. end
  7079.  
  7080. ------------------------------------------------------------------------
  7081. --
  7082. -- * used in multiple locations
  7083. ------------------------------------------------------------------------
  7084. function luaK:exp2anyreg(fs, e)
  7085. self:dischargevars(fs, e)
  7086. if e.k == "VNONRELOC" then
  7087. if not self:hasjumps(e) then -- exp is already in a register
  7088. return e.info
  7089. end
  7090. if e.info >= fs.nactvar then -- reg. is not a local?
  7091. self:exp2reg(fs, e, e.info) -- put value on it
  7092. return e.info
  7093. end
  7094. end
  7095. self:exp2nextreg(fs, e) -- default
  7096. return e.info
  7097. end
  7098.  
  7099. ------------------------------------------------------------------------
  7100. --
  7101. -- * used in luaK:exp2RK(), luaK:prefix(), luaK:posfix()
  7102. -- * used in (lparser) luaY:yindex()
  7103. ------------------------------------------------------------------------
  7104. function luaK:exp2val(fs, e)
  7105. if self:hasjumps(e) then
  7106. self:exp2anyreg(fs, e)
  7107. else
  7108. self:dischargevars(fs, e)
  7109. end
  7110. end
  7111.  
  7112. ------------------------------------------------------------------------
  7113. --
  7114. -- * used in multiple locations
  7115. ------------------------------------------------------------------------
  7116. function luaK:exp2RK(fs, e)
  7117. self:exp2val(fs, e)
  7118. local k = e.k
  7119. if k == "VKNUM" or k == "VTRUE" or k == "VFALSE" or k == "VNIL" then
  7120. if fs.nk <= luaP.MAXINDEXRK then -- constant fit in RK operand?
  7121. -- converted from a 2-deep ternary operator expression
  7122. if e.k == "VNIL" then
  7123. e.info = self:nilK(fs)
  7124. else
  7125. e.info = (e.k == "VKNUM") and self:numberK(fs, e.nval)
  7126. or self:boolK(fs, e.k == "VTRUE")
  7127. end
  7128. e.k = "VK"
  7129. return luaP:RKASK(e.info)
  7130. end
  7131. elseif k == "VK" then
  7132. if e.info <= luaP.MAXINDEXRK then -- constant fit in argC?
  7133. return luaP:RKASK(e.info)
  7134. end
  7135. else
  7136. -- default
  7137. end
  7138. -- not a constant in the right range: put it in a register
  7139. return self:exp2anyreg(fs, e)
  7140. end
  7141.  
  7142. ------------------------------------------------------------------------
  7143. --
  7144. -- * used in (lparser) luaY:assignment(), luaY:localfunc(), luaY:funcstat()
  7145. ------------------------------------------------------------------------
  7146. function luaK:storevar(fs, var, ex)
  7147. local k = var.k
  7148. if k == "VLOCAL" then
  7149. self:freeexp(fs, ex)
  7150. self:exp2reg(fs, ex, var.info)
  7151. return
  7152. elseif k == "VUPVAL" then
  7153. local e = self:exp2anyreg(fs, ex)
  7154. self:codeABC(fs, "OP_SETUPVAL", e, var.info, 0)
  7155. elseif k == "VGLOBAL" then
  7156. local e = self:exp2anyreg(fs, ex)
  7157. self:codeABx(fs, "OP_SETGLOBAL", e, var.info)
  7158. elseif k == "VINDEXED" then
  7159. local e = self:exp2RK(fs, ex)
  7160. self:codeABC(fs, "OP_SETTABLE", var.info, var.aux, e)
  7161. else
  7162. assert(0) -- invalid var kind to store
  7163. end
  7164. self:freeexp(fs, ex)
  7165. end
  7166.  
  7167. ------------------------------------------------------------------------
  7168. --
  7169. -- * used only in (lparser) luaY:primaryexp()
  7170. ------------------------------------------------------------------------
  7171. function luaK:_self(fs, e, key)
  7172. self:exp2anyreg(fs, e)
  7173. self:freeexp(fs, e)
  7174. local func = fs.freereg
  7175. self:reserveregs(fs, 2)
  7176. self:codeABC(fs, "OP_SELF", func, e.info, self:exp2RK(fs, key))
  7177. self:freeexp(fs, key)
  7178. e.info = func
  7179. e.k = "VNONRELOC"
  7180. end
  7181.  
  7182. ------------------------------------------------------------------------
  7183. --
  7184. -- * used in luaK:goiftrue(), luaK:codenot()
  7185. ------------------------------------------------------------------------
  7186. function luaK:invertjump(fs, e)
  7187. local pc = self:getjumpcontrol(fs, e.info)
  7188. assert(luaP:testTMode(luaP:GET_OPCODE(pc)) ~= 0 and
  7189. luaP:GET_OPCODE(pc) ~= "OP_TESTSET" and
  7190. luaP:GET_OPCODE(pc) ~= "OP_TEST")
  7191. luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0)
  7192. end
  7193.  
  7194. ------------------------------------------------------------------------
  7195. --
  7196. -- * used in luaK:goiftrue(), luaK:goiffalse()
  7197. ------------------------------------------------------------------------
  7198. function luaK:jumponcond(fs, e, cond)
  7199. if e.k == "VRELOCABLE" then
  7200. local ie = self:getcode(fs, e)
  7201. if luaP:GET_OPCODE(ie) == "OP_NOT" then
  7202. fs.pc = fs.pc - 1 -- remove previous OP_NOT
  7203. return self:condjump(fs, "OP_TEST", luaP:GETARG_B(ie), 0, cond and 0 or 1)
  7204. end
  7205. -- else go through
  7206. end
  7207. self:discharge2anyreg(fs, e)
  7208. self:freeexp(fs, e)
  7209. return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0)
  7210. end
  7211.  
  7212. ------------------------------------------------------------------------
  7213. --
  7214. -- * used in luaK:infix(), (lparser) luaY:cond()
  7215. ------------------------------------------------------------------------
  7216. function luaK:goiftrue(fs, e)
  7217. local pc -- pc of last jump
  7218. self:dischargevars(fs, e)
  7219. local k = e.k
  7220. if k == "VK" or k == "VKNUM" or k == "VTRUE" then
  7221. pc = self.NO_JUMP -- always true; do nothing
  7222. elseif k == "VFALSE" then
  7223. pc = self:jump(fs) -- always jump
  7224. elseif k == "VJMP" then
  7225. self:invertjump(fs, e)
  7226. pc = e.info
  7227. else
  7228. pc = self:jumponcond(fs, e, false)
  7229. end
  7230. e.f = self:concat(fs, e.f, pc) -- insert last jump in `f' list
  7231. self:patchtohere(fs, e.t)
  7232. e.t = self.NO_JUMP
  7233. end
  7234.  
  7235. ------------------------------------------------------------------------
  7236. --
  7237. -- * used in luaK:infix()
  7238. ------------------------------------------------------------------------
  7239. function luaK:goiffalse(fs, e)
  7240. local pc -- pc of last jump
  7241. self:dischargevars(fs, e)
  7242. local k = e.k
  7243. if k == "VNIL" or k == "VFALSE"then
  7244. pc = self.NO_JUMP -- always false; do nothing
  7245. elseif k == "VTRUE" then
  7246. pc = self:jump(fs) -- always jump
  7247. elseif k == "VJMP" then
  7248. pc = e.info
  7249. else
  7250. pc = self:jumponcond(fs, e, true)
  7251. end
  7252. e.t = self:concat(fs, e.t, pc) -- insert last jump in `t' list
  7253. self:patchtohere(fs, e.f)
  7254. e.f = self.NO_JUMP
  7255. end
  7256.  
  7257. ------------------------------------------------------------------------
  7258. --
  7259. -- * used only in luaK:prefix()
  7260. ------------------------------------------------------------------------
  7261. function luaK:codenot(fs, e)
  7262. self:dischargevars(fs, e)
  7263. local k = e.k
  7264. if k == "VNIL" or k == "VFALSE" then
  7265. e.k = "VTRUE"
  7266. elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then
  7267. e.k = "VFALSE"
  7268. elseif k == "VJMP" then
  7269. self:invertjump(fs, e)
  7270. elseif k == "VRELOCABLE" or k == "VNONRELOC" then
  7271. self:discharge2anyreg(fs, e)
  7272. self:freeexp(fs, e)
  7273. e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0)
  7274. e.k = "VRELOCABLE"
  7275. else
  7276. assert(0) -- cannot happen
  7277. end
  7278. -- interchange true and false lists
  7279. e.f, e.t = e.t, e.f
  7280. self:removevalues(fs, e.f)
  7281. self:removevalues(fs, e.t)
  7282. end
  7283.  
  7284. ------------------------------------------------------------------------
  7285. --
  7286. -- * used in (lparser) luaY:field(), luaY:primaryexp()
  7287. ------------------------------------------------------------------------
  7288. function luaK:indexed(fs, t, k)
  7289. t.aux = self:exp2RK(fs, k)
  7290. t.k = "VINDEXED"
  7291. end
  7292.  
  7293. ------------------------------------------------------------------------
  7294. --
  7295. -- * used only in luaK:codearith()
  7296. ------------------------------------------------------------------------
  7297. function luaK:constfolding(op, e1, e2)
  7298. local r
  7299. if not self:isnumeral(e1) or not self:isnumeral(e2) then return false end
  7300. local v1 = e1.nval
  7301. local v2 = e2.nval
  7302. if op == "OP_ADD" then
  7303. r = self:numadd(v1, v2)
  7304. elseif op == "OP_SUB" then
  7305. r = self:numsub(v1, v2)
  7306. elseif op == "OP_MUL" then
  7307. r = self:nummul(v1, v2)
  7308. elseif op == "OP_DIV" then
  7309. if v2 == 0 then return false end -- do not attempt to divide by 0
  7310. r = self:numdiv(v1, v2)
  7311. elseif op == "OP_MOD" then
  7312. if v2 == 0 then return false end -- do not attempt to divide by 0
  7313. r = self:nummod(v1, v2)
  7314. elseif op == "OP_POW" then
  7315. r = self:numpow(v1, v2)
  7316. elseif op == "OP_UNM" then
  7317. r = self:numunm(v1)
  7318. elseif op == "OP_LEN" then
  7319. return false -- no constant folding for 'len'
  7320. else
  7321. assert(0)
  7322. r = 0
  7323. end
  7324. if self:numisnan(r) then return false end -- do not attempt to produce NaN
  7325. e1.nval = r
  7326. return true
  7327. end
  7328.  
  7329. ------------------------------------------------------------------------
  7330. --
  7331. -- * used in luaK:prefix(), luaK:posfix()
  7332. ------------------------------------------------------------------------
  7333. function luaK:codearith(fs, op, e1, e2)
  7334. if self:constfolding(op, e1, e2) then
  7335. return
  7336. else
  7337. local o2 = (op ~= "OP_UNM" and op ~= "OP_LEN") and self:exp2RK(fs, e2) or 0
  7338. local o1 = self:exp2RK(fs, e1)
  7339. if o1 > o2 then
  7340. self:freeexp(fs, e1)
  7341. self:freeexp(fs, e2)
  7342. else
  7343. self:freeexp(fs, e2)
  7344. self:freeexp(fs, e1)
  7345. end
  7346. e1.info = self:codeABC(fs, op, 0, o1, o2)
  7347. e1.k = "VRELOCABLE"
  7348. end
  7349. end
  7350.  
  7351. ------------------------------------------------------------------------
  7352. --
  7353. -- * used only in luaK:posfix()
  7354. ------------------------------------------------------------------------
  7355. function luaK:codecomp(fs, op, cond, e1, e2)
  7356. local o1 = self:exp2RK(fs, e1)
  7357. local o2 = self:exp2RK(fs, e2)
  7358. self:freeexp(fs, e2)
  7359. self:freeexp(fs, e1)
  7360. if cond == 0 and op ~= "OP_EQ" then
  7361. -- exchange args to replace by `<' or `<='
  7362. o1, o2 = o2, o1 -- o1 <==> o2
  7363. cond = 1
  7364. end
  7365. e1.info = self:condjump(fs, op, cond, o1, o2)
  7366. e1.k = "VJMP"
  7367. end
  7368.  
  7369. ------------------------------------------------------------------------
  7370. --
  7371. -- * used only in (lparser) luaY:subexpr()
  7372. ------------------------------------------------------------------------
  7373. function luaK:prefix(fs, op, e)
  7374. local e2 = {} -- expdesc
  7375. e2.t, e2.f = self.NO_JUMP, self.NO_JUMP
  7376. e2.k = "VKNUM"
  7377. e2.nval = 0
  7378. if op == "OPR_MINUS" then
  7379. if not self:isnumeral(e) then
  7380. self:exp2anyreg(fs, e) -- cannot operate on non-numeric constants
  7381. end
  7382. self:codearith(fs, "OP_UNM", e, e2)
  7383. elseif op == "OPR_NOT" then
  7384. self:codenot(fs, e)
  7385. elseif op == "OPR_LEN" then
  7386. self:exp2anyreg(fs, e) -- cannot operate on constants
  7387. self:codearith(fs, "OP_LEN", e, e2)
  7388. else
  7389. assert(0)
  7390. end
  7391. end
  7392.  
  7393. ------------------------------------------------------------------------
  7394. --
  7395. -- * used only in (lparser) luaY:subexpr()
  7396. ------------------------------------------------------------------------
  7397. function luaK:infix(fs, op, v)
  7398. if op == "OPR_AND" then
  7399. self:goiftrue(fs, v)
  7400. elseif op == "OPR_OR" then
  7401. self:goiffalse(fs, v)
  7402. elseif op == "OPR_CONCAT" then
  7403. self:exp2nextreg(fs, v) -- operand must be on the 'stack'
  7404. elseif op == "OPR_ADD" or op == "OPR_SUB" or
  7405. op == "OPR_MUL" or op == "OPR_DIV" or
  7406. op == "OPR_MOD" or op == "OPR_POW" then
  7407. if not self:isnumeral(v) then self:exp2RK(fs, v) end
  7408. else
  7409. self:exp2RK(fs, v)
  7410. end
  7411. end
  7412.  
  7413. ------------------------------------------------------------------------
  7414. --
  7415. -- * used only in (lparser) luaY:subexpr()
  7416. ------------------------------------------------------------------------
  7417. -- table lookups to simplify testing
  7418. luaK.arith_op = {
  7419. OPR_ADD = "OP_ADD", OPR_SUB = "OP_SUB", OPR_MUL = "OP_MUL",
  7420. OPR_DIV = "OP_DIV", OPR_MOD = "OP_MOD", OPR_POW = "OP_POW",
  7421. }
  7422. luaK.comp_op = {
  7423. OPR_EQ = "OP_EQ", OPR_NE = "OP_EQ", OPR_LT = "OP_LT",
  7424. OPR_LE = "OP_LE", OPR_GT = "OP_LT", OPR_GE = "OP_LE",
  7425. }
  7426. luaK.comp_cond = {
  7427. OPR_EQ = 1, OPR_NE = 0, OPR_LT = 1,
  7428. OPR_LE = 1, OPR_GT = 0, OPR_GE = 0,
  7429. }
  7430. function luaK:posfix(fs, op, e1, e2)
  7431. -- needed because e1 = e2 doesn't copy values...
  7432. -- * in 5.0.x, only k/info/aux/t/f copied, t for AND, f for OR
  7433. -- but here, all elements are copied for completeness' sake
  7434. local function copyexp(e1, e2)
  7435. e1.k = e2.k
  7436. e1.info = e2.info; e1.aux = e2.aux
  7437. e1.nval = e2.nval
  7438. e1.t = e2.t; e1.f = e2.f
  7439. end
  7440. if op == "OPR_AND" then
  7441. assert(e1.t == self.NO_JUMP) -- list must be closed
  7442. self:dischargevars(fs, e2)
  7443. e2.f = self:concat(fs, e2.f, e1.f)
  7444. copyexp(e1, e2)
  7445. elseif op == "OPR_OR" then
  7446. assert(e1.f == self.NO_JUMP) -- list must be closed
  7447. self:dischargevars(fs, e2)
  7448. e2.t = self:concat(fs, e2.t, e1.t)
  7449. copyexp(e1, e2)
  7450. elseif op == "OPR_CONCAT" then
  7451. self:exp2val(fs, e2)
  7452. if e2.k == "VRELOCABLE" and luaP:GET_OPCODE(self:getcode(fs, e2)) == "OP_CONCAT" then
  7453. assert(e1.info == luaP:GETARG_B(self:getcode(fs, e2)) - 1)
  7454. self:freeexp(fs, e1)
  7455. luaP:SETARG_B(self:getcode(fs, e2), e1.info)
  7456. e1.k = "VRELOCABLE"
  7457. e1.info = e2.info
  7458. else
  7459. self:exp2nextreg(fs, e2) -- operand must be on the 'stack'
  7460. self:codearith(fs, "OP_CONCAT", e1, e2)
  7461. end
  7462. else
  7463. -- the following uses a table lookup in place of conditionals
  7464. local arith = self.arith_op[op]
  7465. if arith then
  7466. self:codearith(fs, arith, e1, e2)
  7467. else
  7468. local comp = self.comp_op[op]
  7469. if comp then
  7470. self:codecomp(fs, comp, self.comp_cond[op], e1, e2)
  7471. else
  7472. assert(0)
  7473. end
  7474. end--if arith
  7475. end--if op
  7476. end
  7477.  
  7478. ------------------------------------------------------------------------
  7479. -- adjusts debug information for last instruction written, in order to
  7480. -- change the line where item comes into existence
  7481. -- * used in (lparser) luaY:funcargs(), luaY:forbody(), luaY:funcstat()
  7482. ------------------------------------------------------------------------
  7483. function luaK:fixline(fs, line)
  7484. fs.f.lineinfo[fs.pc - 1] = line
  7485. end
  7486.  
  7487. ------------------------------------------------------------------------
  7488. -- general function to write an instruction into the instruction buffer,
  7489. -- sets debug information too
  7490. -- * used in luaK:codeABC(), luaK:codeABx()
  7491. -- * called directly by (lparser) luaY:whilestat()
  7492. ------------------------------------------------------------------------
  7493. function luaK:code(fs, i, line)
  7494. local f = fs.f
  7495. self:dischargejpc(fs) -- 'pc' will change
  7496. -- put new instruction in code array
  7497. luaY:growvector(fs.L, f.code, fs.pc, f.sizecode, nil,
  7498. luaY.MAX_INT, "code size overflow")
  7499. f.code[fs.pc] = i
  7500. -- save corresponding line information
  7501. luaY:growvector(fs.L, f.lineinfo, fs.pc, f.sizelineinfo, nil,
  7502. luaY.MAX_INT, "code size overflow")
  7503. f.lineinfo[fs.pc] = line
  7504. local pc = fs.pc
  7505. fs.pc = fs.pc + 1
  7506. return pc
  7507. end
  7508.  
  7509. ------------------------------------------------------------------------
  7510. -- writes an instruction of type ABC
  7511. -- * calls luaK:code()
  7512. ------------------------------------------------------------------------
  7513. function luaK:codeABC(fs, o, a, b, c)
  7514. assert(luaP:getOpMode(o) == luaP.OpMode.iABC)
  7515. assert(luaP:getBMode(o) ~= luaP.OpArgMask.OpArgN or b == 0)
  7516. assert(luaP:getCMode(o) ~= luaP.OpArgMask.OpArgN or c == 0)
  7517. return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline)
  7518. end
  7519.  
  7520. ------------------------------------------------------------------------
  7521. -- writes an instruction of type ABx
  7522. -- * calls luaK:code(), called by luaK:codeAsBx()
  7523. ------------------------------------------------------------------------
  7524. function luaK:codeABx(fs, o, a, bc)
  7525. assert(luaP:getOpMode(o) == luaP.OpMode.iABx or
  7526. luaP:getOpMode(o) == luaP.OpMode.iAsBx)
  7527. assert(luaP:getCMode(o) == luaP.OpArgMask.OpArgN)
  7528. return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline)
  7529. end
  7530.  
  7531. ------------------------------------------------------------------------
  7532. --
  7533. -- * used in (lparser) luaY:closelistfield(), luaY:lastlistfield()
  7534. ------------------------------------------------------------------------
  7535. function luaK:setlist(fs, base, nelems, tostore)
  7536. local c = math.floor((nelems - 1)/luaP.LFIELDS_PER_FLUSH) + 1
  7537. local b = (tostore == luaY.LUA_MULTRET) and 0 or tostore
  7538. assert(tostore ~= 0)
  7539. if c <= luaP.MAXARG_C then
  7540. self:codeABC(fs, "OP_SETLIST", base, b, c)
  7541. else
  7542. self:codeABC(fs, "OP_SETLIST", base, b, 0)
  7543. self:code(fs, luaP:CREATE_Inst(c), fs.ls.lastline)
  7544. end
  7545. fs.freereg = base + 1 -- free registers with list values
  7546. end
  7547.  
  7548. return function(a) luaY = a return luaK end]]></ProtectedString>
  7549. <BinaryString name="Tags"></BinaryString>
  7550. </Properties>
  7551. </Item>
  7552. <Item class="ModuleScript" referent="RBX5721C2C4E9AA4045A3AE5FC31529EF48">
  7553. <Properties>
  7554. <Content name="LinkedSource"><null></null></Content>
  7555. <string name="Name">LuaU</string>
  7556. <string name="ScriptGuid">{9C277632-5516-4FB9-AC62-AC3F3BE90D9E}</string>
  7557. <ProtectedString name="Source"><![CDATA[--[[--------------------------------------------------------------------
  7558.  
  7559. ldump.lua
  7560. Save precompiled Lua chunks
  7561. This file is part of Yueliang.
  7562.  
  7563. Copyright (c) 2006 Kein-Hong Man <[email protected]>
  7564. The COPYRIGHT file describes the conditions
  7565. under which this software may be distributed.
  7566.  
  7567. See the ChangeLog for more information.
  7568.  
  7569. ----------------------------------------------------------------------]]
  7570.  
  7571. --[[--------------------------------------------------------------------
  7572. -- Notes:
  7573. -- * WARNING! byte order (little endian) and data type sizes for header
  7574. -- signature values hard-coded; see luaU:header
  7575. -- * chunk writer generators are included, see below
  7576. -- * one significant difference is that instructions are still in table
  7577. -- form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to
  7578. -- convert them into 4-char strings
  7579. --
  7580. -- Not implemented:
  7581. -- * DumpVar, DumpMem has been removed
  7582. -- * DumpVector folded into folded into DumpDebug, DumpCode
  7583. --
  7584. -- Added:
  7585. -- * for convenience, the following two functions have been added:
  7586. -- luaU:make_setS: create a chunk writer that writes to a string
  7587. -- luaU:make_setF: create a chunk writer that writes to a file
  7588. -- (lua.h contains a typedef for lua_Writer/lua_Chunkwriter, and
  7589. -- a Lua-based implementation exists, writer() in lstrlib.c)
  7590. -- * luaU:ttype(o) (from lobject.h)
  7591. -- * for converting number types to its binary equivalent:
  7592. -- luaU:from_double(x): encode double value for writing
  7593. -- luaU:from_int(x): encode integer value for writing
  7594. -- (error checking is limited for these conversion functions)
  7595. -- (double conversion does not support denormals or NaNs)
  7596. --
  7597. -- Changed in 5.1.x:
  7598. -- * the dumper was mostly rewritten in Lua 5.1.x, so notes on the
  7599. -- differences between 5.0.x and 5.1.x is limited
  7600. -- * LUAC_VERSION bumped to 0x51, LUAC_FORMAT added
  7601. -- * developer is expected to adjust LUAC_FORMAT in order to identify
  7602. -- non-standard binary chunk formats
  7603. -- * header signature code is smaller, has been simplified, and is
  7604. -- tested as a single unit; its logic is shared with the undumper
  7605. -- * no more endian conversion, invalid endianness mean rejection
  7606. -- * opcode field sizes are no longer exposed in the header
  7607. -- * code moved to front of a prototype, followed by constants
  7608. -- * debug information moved to the end of the binary chunk, and the
  7609. -- relevant functions folded into a single function
  7610. -- * luaU:dump returns a writer status code
  7611. -- * chunk writer now implements status code because dumper uses it
  7612. -- * luaU:endianness removed
  7613. ----------------------------------------------------------------------]]
  7614.  
  7615. --requires luaP
  7616. local luaU = {}
  7617. local luaP = require(script.Parent.LuaP)
  7618.  
  7619. -- mark for precompiled code ('<esc>Lua') (from lua.h)
  7620. luaU.LUA_SIGNATURE = "\27Lua"
  7621.  
  7622. -- constants used by dumper (from lua.h)
  7623. luaU.LUA_TNUMBER = 3
  7624. luaU.LUA_TSTRING = 4
  7625. luaU.LUA_TNIL = 0
  7626. luaU.LUA_TBOOLEAN = 1
  7627. luaU.LUA_TNONE = -1
  7628.  
  7629. -- constants for header of binary files (from lundump.h)
  7630. luaU.LUAC_VERSION = 0x51 -- this is Lua 5.1
  7631. luaU.LUAC_FORMAT = 0 -- this is the official format
  7632. luaU.LUAC_HEADERSIZE = 12 -- size of header of binary files
  7633.  
  7634. --[[--------------------------------------------------------------------
  7635. -- Additional functions to handle chunk writing
  7636. -- * to use make_setS and make_setF, see test_ldump.lua elsewhere
  7637. ----------------------------------------------------------------------]]
  7638.  
  7639. ------------------------------------------------------------------------
  7640. -- create a chunk writer that writes to a string
  7641. -- * returns the writer function and a table containing the string
  7642. -- * to get the final result, look in buff.data
  7643. ------------------------------------------------------------------------
  7644. function luaU:make_setS()
  7645. local buff = {}
  7646. buff.data = ""
  7647. local writer =
  7648. function(s, buff) -- chunk writer
  7649. if not s then return 0 end
  7650. buff.data = buff.data..s
  7651. return 0
  7652. end
  7653. return writer, buff
  7654. end
  7655.  
  7656. ------------------------------------------------------------------------
  7657. -- create a chunk writer that writes to a file
  7658. -- * returns the writer function and a table containing the file handle
  7659. -- * if a nil is passed, then writer should close the open file
  7660. ------------------------------------------------------------------------
  7661.  
  7662. --[[
  7663. function luaU:make_setF(filename)
  7664. local buff = {}
  7665. buff.h = io.open(filename, "wb")
  7666. if not buff.h then return nil end
  7667. local writer =
  7668. function(s, buff) -- chunk writer
  7669. if not buff.h then return 0 end
  7670. if not s then
  7671. if buff.h:close() then return 0 end
  7672. else
  7673. if buff.h:write(s) then return 0 end
  7674. end
  7675. return 1
  7676. end
  7677. return writer, buff
  7678. end--]]
  7679.  
  7680. ------------------------------------------------------------------------
  7681. -- works like the lobject.h version except that TObject used in these
  7682. -- scripts only has a 'value' field, no 'tt' field (native types used)
  7683. ------------------------------------------------------------------------
  7684. function luaU:ttype(o)
  7685. local tt = type(o.value)
  7686. if tt == "number" then return self.LUA_TNUMBER
  7687. elseif tt == "string" then return self.LUA_TSTRING
  7688. elseif tt == "nil" then return self.LUA_TNIL
  7689. elseif tt == "boolean" then return self.LUA_TBOOLEAN
  7690. else
  7691. return self.LUA_TNONE -- the rest should not appear
  7692. end
  7693. end
  7694.  
  7695. -----------------------------------------------------------------------
  7696. -- converts a IEEE754 double number to an 8-byte little-endian string
  7697. -- * luaU:from_double() and luaU:from_int() are adapted from ChunkBake
  7698. -- * supports +/- Infinity, but not denormals or NaNs
  7699. -----------------------------------------------------------------------
  7700. function luaU:from_double(x)
  7701. local function grab_byte(v)
  7702. local c = v % 256
  7703. return (v - c) / 256, string.char(c)
  7704. end
  7705. local sign = 0
  7706. if x < 0 then sign = 1; x = -x end
  7707. local mantissa, exponent = math.frexp(x)
  7708. if x == 0 then -- zero
  7709. mantissa, exponent = 0, 0
  7710. elseif x == 1/0 then
  7711. mantissa, exponent = 0, 2047
  7712. else
  7713. mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
  7714. exponent = exponent + 1022
  7715. end
  7716. local v, byte = "" -- convert to bytes
  7717. x = math.floor(mantissa)
  7718. for i = 1,6 do
  7719. x, byte = grab_byte(x); v = v..byte -- 47:0
  7720. end
  7721. x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
  7722. x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
  7723. return v
  7724. end
  7725.  
  7726. -----------------------------------------------------------------------
  7727. -- converts a number to a little-endian 32-bit integer string
  7728. -- * input value assumed to not overflow, can be signed/unsigned
  7729. -----------------------------------------------------------------------
  7730. function luaU:from_int(x)
  7731. local v = ""
  7732. x = math.floor(x)
  7733. if x < 0 then x = 4294967296 + x end -- ULONG_MAX+1
  7734. for i = 1, 4 do
  7735. local c = x % 256
  7736. v = v..string.char(c); x = math.floor(x / 256)
  7737. end
  7738. return v
  7739. end
  7740.  
  7741. --[[--------------------------------------------------------------------
  7742. -- Functions to make a binary chunk
  7743. -- * many functions have the size parameter removed, since output is
  7744. -- in the form of a string and some sizes are implicit or hard-coded
  7745. ----------------------------------------------------------------------]]
  7746.  
  7747. --[[--------------------------------------------------------------------
  7748. -- struct DumpState:
  7749. -- L -- lua_State (not used in this script)
  7750. -- writer -- lua_Writer (chunk writer function)
  7751. -- data -- void* (chunk writer context or data already written)
  7752. -- strip -- if true, don't write any debug information
  7753. -- status -- if non-zero, an error has occured
  7754. ----------------------------------------------------------------------]]
  7755.  
  7756. ------------------------------------------------------------------------
  7757. -- dumps a block of bytes
  7758. -- * lua_unlock(D.L), lua_lock(D.L) unused
  7759. ------------------------------------------------------------------------
  7760. function luaU:DumpBlock(b, D)
  7761. if D.status == 0 then
  7762. -- lua_unlock(D->L);
  7763. D.status = D.write(b, D.data)
  7764. -- lua_lock(D->L);
  7765. end
  7766. end
  7767.  
  7768. ------------------------------------------------------------------------
  7769. -- dumps a char
  7770. ------------------------------------------------------------------------
  7771. function luaU:DumpChar(y, D)
  7772. self:DumpBlock(string.char(y), D)
  7773. end
  7774.  
  7775. ------------------------------------------------------------------------
  7776. -- dumps a 32-bit signed or unsigned integer (for int) (hard-coded)
  7777. ------------------------------------------------------------------------
  7778. function luaU:DumpInt(x, D)
  7779. self:DumpBlock(self:from_int(x), D)
  7780. end
  7781.  
  7782. ------------------------------------------------------------------------
  7783. -- dumps a lua_Number (hard-coded as a double)
  7784. ------------------------------------------------------------------------
  7785. function luaU:DumpNumber(x, D)
  7786. self:DumpBlock(self:from_double(x), D)
  7787. end
  7788.  
  7789. ------------------------------------------------------------------------
  7790. -- dumps a Lua string (size type is hard-coded)
  7791. ------------------------------------------------------------------------
  7792. function luaU:DumpString(s, D)
  7793. if s == nil then
  7794. self:DumpInt(0, D)
  7795. else
  7796. s = s.."\0" -- include trailing '\0'
  7797. self:DumpInt(#s, D)
  7798. self:DumpBlock(s, D)
  7799. end
  7800. end
  7801.  
  7802. ------------------------------------------------------------------------
  7803. -- dumps instruction block from function prototype
  7804. ------------------------------------------------------------------------
  7805. function luaU:DumpCode(f, D)
  7806. local n = f.sizecode
  7807. --was DumpVector
  7808. self:DumpInt(n, D)
  7809. for i = 0, n - 1 do
  7810. self:DumpBlock(luaP:Instruction(f.code[i]), D)
  7811. end
  7812. end
  7813.  
  7814. ------------------------------------------------------------------------
  7815. -- dump constant pool from function prototype
  7816. -- * bvalue(o), nvalue(o) and rawtsvalue(o) macros removed
  7817. ------------------------------------------------------------------------
  7818. function luaU:DumpConstants(f, D)
  7819. local n = f.sizek
  7820. self:DumpInt(n, D)
  7821. for i = 0, n - 1 do
  7822. local o = f.k[i] -- TValue
  7823. local tt = self:ttype(o)
  7824. self:DumpChar(tt, D)
  7825. if tt == self.LUA_TNIL then
  7826. elseif tt == self.LUA_TBOOLEAN then
  7827. self:DumpChar(o.value and 1 or 0, D)
  7828. elseif tt == self.LUA_TNUMBER then
  7829. self:DumpNumber(o.value, D)
  7830. elseif tt == self.LUA_TSTRING then
  7831. self:DumpString(o.value, D)
  7832. else
  7833. --lua_assert(0) -- cannot happen
  7834. end
  7835. end
  7836. n = f.sizep
  7837. self:DumpInt(n, D)
  7838. for i = 0, n - 1 do
  7839. self:DumpFunction(f.p[i], f.source, D)
  7840. end
  7841. end
  7842.  
  7843. ------------------------------------------------------------------------
  7844. -- dump debug information
  7845. ------------------------------------------------------------------------
  7846. function luaU:DumpDebug(f, D)
  7847. local n
  7848. n = D.strip and 0 or f.sizelineinfo -- dump line information
  7849. --was DumpVector
  7850. self:DumpInt(n, D)
  7851. for i = 0, n - 1 do
  7852. self:DumpInt(f.lineinfo[i], D)
  7853. end
  7854. n = D.strip and 0 or f.sizelocvars -- dump local information
  7855. self:DumpInt(n, D)
  7856. for i = 0, n - 1 do
  7857. self:DumpString(f.locvars[i].varname, D)
  7858. self:DumpInt(f.locvars[i].startpc, D)
  7859. self:DumpInt(f.locvars[i].endpc, D)
  7860. end
  7861. n = D.strip and 0 or f.sizeupvalues -- dump upvalue information
  7862. self:DumpInt(n, D)
  7863. for i = 0, n - 1 do
  7864. self:DumpString(f.upvalues[i], D)
  7865. end
  7866. end
  7867.  
  7868. ------------------------------------------------------------------------
  7869. -- dump child function prototypes from function prototype
  7870. ------------------------------------------------------------------------
  7871. function luaU:DumpFunction(f, p, D)
  7872. local source = f.source
  7873. if source == p or D.strip then source = nil end
  7874. self:DumpString(source, D)
  7875. self:DumpInt(f.lineDefined, D)
  7876. self:DumpInt(f.lastlinedefined, D)
  7877. self:DumpChar(f.nups, D)
  7878. self:DumpChar(f.numparams, D)
  7879. self:DumpChar(f.is_vararg, D)
  7880. self:DumpChar(f.maxstacksize, D)
  7881. self:DumpCode(f, D)
  7882. self:DumpConstants(f, D)
  7883. self:DumpDebug(f, D)
  7884. end
  7885.  
  7886. ------------------------------------------------------------------------
  7887. -- dump Lua header section (some sizes hard-coded)
  7888. ------------------------------------------------------------------------
  7889. function luaU:DumpHeader(D)
  7890. local h = self:header()
  7891. assert(#h == self.LUAC_HEADERSIZE) -- fixed buffer now an assert
  7892. self:DumpBlock(h, D)
  7893. end
  7894.  
  7895. ------------------------------------------------------------------------
  7896. -- make header (from lundump.c)
  7897. -- returns the header string
  7898. ------------------------------------------------------------------------
  7899. function luaU:header()
  7900. local x = 1
  7901. return self.LUA_SIGNATURE..
  7902. string.char(
  7903. self.LUAC_VERSION,
  7904. self.LUAC_FORMAT,
  7905. x, -- endianness (1=little)
  7906. 4, -- sizeof(int)
  7907. 4, -- sizeof(size_t)
  7908. 4, -- sizeof(Instruction)
  7909. 8, -- sizeof(lua_Number)
  7910. 0) -- is lua_Number integral?
  7911. end
  7912.  
  7913. ------------------------------------------------------------------------
  7914. -- dump Lua function as precompiled chunk
  7915. -- (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
  7916. -- * w, data are created from make_setS, make_setF
  7917. ------------------------------------------------------------------------
  7918. function luaU:dump(L, f, w, data, strip)
  7919. local D = {} -- DumpState
  7920. D.L = L
  7921. D.write = w
  7922. D.data = data
  7923. D.strip = strip
  7924. D.status = 0
  7925. self:DumpHeader(D)
  7926. self:DumpFunction(f, nil, D)
  7927. -- added: for a chunk writer writing to a file, this final call with
  7928. -- nil data is to indicate to the writer to close the file
  7929. D.write(nil, D.data)
  7930. return D.status
  7931. end
  7932.  
  7933. return luaU]]></ProtectedString>
  7934. <BinaryString name="Tags"></BinaryString>
  7935. </Properties>
  7936. </Item>
  7937. <Item class="ModuleScript" referent="RBX860D6B646D15448DA00363761F66761F">
  7938. <Properties>
  7939. <Content name="LinkedSource"><null></null></Content>
  7940. <string name="Name">LuaP</string>
  7941. <string name="ScriptGuid">{F6F5E123-B39B-4C8A-B113-E644BAE8AA75}</string>
  7942. <ProtectedString name="Source"><![CDATA[--[[--------------------------------------------------------------------
  7943.  
  7944. lopcodes.lua
  7945. Lua 5 virtual machine opcodes in Lua
  7946. This file is part of Yueliang.
  7947.  
  7948. Copyright (c) 2006 Kein-Hong Man <[email protected]>
  7949. The COPYRIGHT file describes the conditions
  7950. under which this software may be distributed.
  7951.  
  7952. See the ChangeLog for more information.
  7953.  
  7954. ----------------------------------------------------------------------]]
  7955.  
  7956. --[[--------------------------------------------------------------------
  7957. -- Notes:
  7958. -- * an Instruction is a table with OP, A, B, C, Bx elements; this
  7959. -- makes the code easy to follow and should allow instruction handling
  7960. -- to work with doubles and ints
  7961. -- * WARNING luaP:Instruction outputs instructions encoded in little-
  7962. -- endian form and field size and positions are hard-coded
  7963. --
  7964. -- Not implemented:
  7965. -- *
  7966. --
  7967. -- Added:
  7968. -- * luaP:CREATE_Inst(c): create an inst from a number (for OP_SETLIST)
  7969. -- * luaP:Instruction(i): convert field elements to a 4-char string
  7970. -- * luaP:DecodeInst(x): convert 4-char string into field elements
  7971. --
  7972. -- Changed in 5.1.x:
  7973. -- * POS_OP added, instruction field positions changed
  7974. -- * some symbol names may have changed, e.g. LUAI_BITSINT
  7975. -- * new operators for RK indices: BITRK, ISK(x), INDEXK(r), RKASK(x)
  7976. -- * OP_MOD, OP_LEN is new
  7977. -- * OP_TEST is now OP_TESTSET, OP_TEST is new
  7978. -- * OP_FORLOOP, OP_TFORLOOP adjusted, OP_FORPREP is new
  7979. -- * OP_TFORPREP deleted
  7980. -- * OP_SETLIST and OP_SETLISTO merged and extended
  7981. -- * OP_VARARG is new
  7982. -- * many changes to implementation of OpMode data
  7983. ----------------------------------------------------------------------]]
  7984.  
  7985. local luaP = {}
  7986.  
  7987. --[[
  7988. ===========================================================================
  7989. We assume that instructions are unsigned numbers.
  7990. All instructions have an opcode in the first 6 bits.
  7991. Instructions can have the following fields:
  7992. 'A' : 8 bits
  7993. 'B' : 9 bits
  7994. 'C' : 9 bits
  7995. 'Bx' : 18 bits ('B' and 'C' together)
  7996. 'sBx' : signed Bx
  7997.  
  7998. A signed argument is represented in excess K; that is, the number
  7999. value is the unsigned value minus K. K is exactly the maximum value
  8000. for that argument (so that -max is represented by 0, and +max is
  8001. represented by 2*max), which is half the maximum for the corresponding
  8002. unsigned argument.
  8003. ===========================================================================
  8004. --]]
  8005.  
  8006. luaP.OpMode = { iABC = 0, iABx = 1, iAsBx = 2 } -- basic instruction format
  8007.  
  8008. ------------------------------------------------------------------------
  8009. -- size and position of opcode arguments.
  8010. -- * WARNING size and position is hard-coded elsewhere in this script
  8011. ------------------------------------------------------------------------
  8012. luaP.SIZE_C = 9
  8013. luaP.SIZE_B = 9
  8014. luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B
  8015. luaP.SIZE_A = 8
  8016.  
  8017. luaP.SIZE_OP = 6
  8018.  
  8019. luaP.POS_OP = 0
  8020. luaP.POS_A = luaP.POS_OP + luaP.SIZE_OP
  8021. luaP.POS_C = luaP.POS_A + luaP.SIZE_A
  8022. luaP.POS_B = luaP.POS_C + luaP.SIZE_C
  8023. luaP.POS_Bx = luaP.POS_C
  8024.  
  8025. ------------------------------------------------------------------------
  8026. -- limits for opcode arguments.
  8027. -- we use (signed) int to manipulate most arguments,
  8028. -- so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
  8029. ------------------------------------------------------------------------
  8030. -- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is
  8031. -- running on a Lua VM with double or int as LUA_NUMBER
  8032.  
  8033. luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1
  8034. luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed
  8035.  
  8036. luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1
  8037. luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1
  8038. luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1
  8039.  
  8040. -- creates a mask with 'n' 1 bits at position 'p'
  8041. -- MASK1(n,p) deleted, not required
  8042. -- creates a mask with 'n' 0 bits at position 'p'
  8043. -- MASK0(n,p) deleted, not required
  8044.  
  8045. --[[--------------------------------------------------------------------
  8046. Visual representation for reference:
  8047.  
  8048. 31 | | | 0 bit position
  8049. +-----+-----+-----+----------+
  8050. | B | C | A | Opcode | iABC format
  8051. +-----+-----+-----+----------+
  8052. - 9 - 9 - 8 - 6 - field sizes
  8053. +-----+-----+-----+----------+
  8054. | [s]Bx | A | Opcode | iABx | iAsBx format
  8055. +-----+-----+-----+----------+
  8056.  
  8057. ----------------------------------------------------------------------]]
  8058.  
  8059. ------------------------------------------------------------------------
  8060. -- the following macros help to manipulate instructions
  8061. -- * changed to a table object representation, very clean compared to
  8062. -- the [nightmare] alternatives of using a number or a string
  8063. -- * Bx is a separate element from B and C, since there is never a need
  8064. -- to split Bx in the parser or code generator
  8065. ------------------------------------------------------------------------
  8066.  
  8067. -- these accept or return opcodes in the form of string names
  8068. function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end
  8069. function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end
  8070.  
  8071. function luaP:GETARG_A(i) return i.A end
  8072. function luaP:SETARG_A(i, u) i.A = u end
  8073.  
  8074. function luaP:GETARG_B(i) return i.B end
  8075. function luaP:SETARG_B(i, b) i.B = b end
  8076.  
  8077. function luaP:GETARG_C(i) return i.C end
  8078. function luaP:SETARG_C(i, b) i.C = b end
  8079.  
  8080. function luaP:GETARG_Bx(i) return i.Bx end
  8081. function luaP:SETARG_Bx(i, b) i.Bx = b end
  8082.  
  8083. function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end
  8084. function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end
  8085.  
  8086. function luaP:CREATE_ABC(o,a,b,c)
  8087. return {OP = self.OpCode[o], A = a, B = b, C = c}
  8088. end
  8089.  
  8090. function luaP:CREATE_ABx(o,a,bc)
  8091. return {OP = self.OpCode[o], A = a, Bx = bc}
  8092. end
  8093.  
  8094. ------------------------------------------------------------------------
  8095. -- create an instruction from a number (for OP_SETLIST)
  8096. ------------------------------------------------------------------------
  8097. function luaP:CREATE_Inst(c)
  8098. local o = c % 64
  8099. c = (c - o) / 64
  8100. local a = c % 256
  8101. c = (c - a) / 256
  8102. return self:CREATE_ABx(o, a, c)
  8103. end
  8104.  
  8105. ------------------------------------------------------------------------
  8106. -- returns a 4-char string little-endian encoded form of an instruction
  8107. ------------------------------------------------------------------------
  8108. function luaP:Instruction(i)
  8109. if i.Bx then
  8110. -- change to OP/A/B/C format
  8111. i.C = i.Bx % 512
  8112. i.B = (i.Bx - i.C) / 512
  8113. end
  8114. local I = i.A * 64 + i.OP
  8115. local c0 = I % 256
  8116. I = i.C * 64 + (I - c0) / 256 -- 6 bits of A left
  8117. local c1 = I % 256
  8118. I = i.B * 128 + (I - c1) / 256 -- 7 bits of C left
  8119. local c2 = I % 256
  8120. local c3 = (I - c2) / 256
  8121. return string.char(c0, c1, c2, c3)
  8122. end
  8123.  
  8124. ------------------------------------------------------------------------
  8125. -- decodes a 4-char little-endian string into an instruction struct
  8126. ------------------------------------------------------------------------
  8127. function luaP:DecodeInst(x)
  8128. local byte = string.byte
  8129. local i = {}
  8130. local I = byte(x, 1)
  8131. local op = I % 64
  8132. i.OP = op
  8133. I = byte(x, 2) * 4 + (I - op) / 64 -- 2 bits of c0 left
  8134. local a = I % 256
  8135. i.A = a
  8136. I = byte(x, 3) * 4 + (I - a) / 256 -- 2 bits of c1 left
  8137. local c = I % 512
  8138. i.C = c
  8139. i.B = byte(x, 4) * 2 + (I - c) / 512 -- 1 bits of c2 left
  8140. local opmode = self.OpMode[tonumber(string.sub(self.opmodes[op + 1], 7, 7))]
  8141. if opmode ~= "iABC" then
  8142. i.Bx = i.B * 512 + i.C
  8143. end
  8144. return i
  8145. end
  8146.  
  8147. ------------------------------------------------------------------------
  8148. -- Macros to operate RK indices
  8149. -- * these use arithmetic instead of bit ops
  8150. ------------------------------------------------------------------------
  8151.  
  8152. -- this bit 1 means constant (0 means register)
  8153. luaP.BITRK = math.ldexp(1, luaP.SIZE_B - 1)
  8154.  
  8155. -- test whether value is a constant
  8156. function luaP:ISK(x) return x >= self.BITRK end
  8157.  
  8158. -- gets the index of the constant
  8159. function luaP:INDEXK(x) return x - self.BITRK end
  8160.  
  8161. luaP.MAXINDEXRK = luaP.BITRK - 1
  8162.  
  8163. -- code a constant index as a RK value
  8164. function luaP:RKASK(x) return x + self.BITRK end
  8165.  
  8166. ------------------------------------------------------------------------
  8167. -- invalid register that fits in 8 bits
  8168. ------------------------------------------------------------------------
  8169. luaP.NO_REG = luaP.MAXARG_A
  8170.  
  8171. ------------------------------------------------------------------------
  8172. -- R(x) - register
  8173. -- Kst(x) - constant (in constant table)
  8174. -- RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
  8175. ------------------------------------------------------------------------
  8176.  
  8177. ------------------------------------------------------------------------
  8178. -- grep "ORDER OP" if you change these enums
  8179. ------------------------------------------------------------------------
  8180.  
  8181. --[[--------------------------------------------------------------------
  8182. Lua virtual machine opcodes (enum OpCode):
  8183. ------------------------------------------------------------------------
  8184. name args description
  8185. ------------------------------------------------------------------------
  8186. OP_MOVE A B R(A) := R(B)
  8187. OP_LOADK A Bx R(A) := Kst(Bx)
  8188. OP_LOADBOOL A B C R(A) := (Bool)B; if (C) pc++
  8189. OP_LOADNIL A B R(A) := ... := R(B) := nil
  8190. OP_GETUPVAL A B R(A) := UpValue[B]
  8191. OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
  8192. OP_GETTABLE A B C R(A) := R(B)[RK(C)]
  8193. OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
  8194. OP_SETUPVAL A B UpValue[B] := R(A)
  8195. OP_SETTABLE A B C R(A)[RK(B)] := RK(C)
  8196. OP_NEWTABLE A B C R(A) := {} (size = B,C)
  8197. OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)]
  8198. OP_ADD A B C R(A) := RK(B) + RK(C)
  8199. OP_SUB A B C R(A) := RK(B) - RK(C)
  8200. OP_MUL A B C R(A) := RK(B) * RK(C)
  8201. OP_DIV A B C R(A) := RK(B) / RK(C)
  8202. OP_MOD A B C R(A) := RK(B) % RK(C)
  8203. OP_POW A B C R(A) := RK(B) ^ RK(C)
  8204. OP_UNM A B R(A) := -R(B)
  8205. OP_NOT A B R(A) := not R(B)
  8206. OP_LEN A B R(A) := length of R(B)
  8207. OP_CONCAT A B C R(A) := R(B).. ... ..R(C)
  8208. OP_JMP sBx pc+=sBx
  8209. OP_EQ A B C if ((RK(B) == RK(C)) ~= A) then pc++
  8210. OP_LT A B C if ((RK(B) < RK(C)) ~= A) then pc++
  8211. OP_LE A B C if ((RK(B) <= RK(C)) ~= A) then pc++
  8212. OP_TEST A C if not (R(A) <=> C) then pc++
  8213. OP_TESTSET A B C if (R(B) <=> C) then R(A) := R(B) else pc++
  8214. OP_CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
  8215. OP_TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1))
  8216. OP_RETURN A B return R(A), ... ,R(A+B-2) (see note)
  8217. OP_FORLOOP A sBx R(A)+=R(A+2);
  8218. if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
  8219. OP_FORPREP A sBx R(A)-=R(A+2); pc+=sBx
  8220. OP_TFORLOOP A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
  8221. if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++
  8222. OP_SETLIST A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
  8223. OP_CLOSE A close all variables in the stack up to (>=) R(A)
  8224. OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
  8225. OP_VARARG A B R(A), R(A+1), ..., R(A+B-1) = vararg
  8226. ----------------------------------------------------------------------]]
  8227.  
  8228. luaP.opnames = {} -- opcode names
  8229. luaP.OpCode = {} -- lookup name -> number
  8230. luaP.ROpCode = {} -- lookup number -> name
  8231.  
  8232. ------------------------------------------------------------------------
  8233. -- ORDER OP
  8234. ------------------------------------------------------------------------
  8235. local i = 0
  8236. for v in string.gmatch([[
  8237. MOVE LOADK LOADBOOL LOADNIL GETUPVAL
  8238. GETGLOBAL GETTABLE SETGLOBAL SETUPVAL SETTABLE
  8239. NEWTABLE SELF ADD SUB MUL
  8240. DIV MOD POW UNM NOT
  8241. LEN CONCAT JMP EQ LT
  8242. LE TEST TESTSET CALL TAILCALL
  8243. RETURN FORLOOP FORPREP TFORLOOP SETLIST
  8244. CLOSE CLOSURE VARARG
  8245. ]], "%S+") do
  8246. local n = "OP_"..v
  8247. luaP.opnames[i] = v
  8248. luaP.OpCode[n] = i
  8249. luaP.ROpCode[i] = n
  8250. i = i + 1
  8251. end
  8252. luaP.NUM_OPCODES = i
  8253.  
  8254. --[[
  8255. ===========================================================================
  8256. Notes:
  8257. (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
  8258. and can be 0: OP_CALL then sets 'top' to last_result+1, so
  8259. next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'.
  8260. (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
  8261. set top (like in OP_CALL with C == 0).
  8262. (*) In OP_RETURN, if (B == 0) then return up to 'top'
  8263. (*) In OP_SETLIST, if (B == 0) then B = 'top';
  8264. if (C == 0) then next 'instruction' is real C
  8265. (*) For comparisons, A specifies what condition the test should accept
  8266. (true or false).
  8267. (*) All 'skips' (pc++) assume that next instruction is a jump
  8268. ===========================================================================
  8269. --]]
  8270.  
  8271. --[[--------------------------------------------------------------------
  8272. masks for instruction properties. The format is:
  8273. bits 0-1: op mode
  8274. bits 2-3: C arg mode
  8275. bits 4-5: B arg mode
  8276. bit 6: instruction set register A
  8277. bit 7: operator is a test
  8278.  
  8279. for OpArgMask:
  8280. OpArgN - argument is not used
  8281. OpArgU - argument is used
  8282. OpArgR - argument is a register or a jump offset
  8283. OpArgK - argument is a constant or register/constant
  8284. ----------------------------------------------------------------------]]
  8285.  
  8286. -- was enum OpArgMask
  8287. luaP.OpArgMask = { OpArgN = 0, OpArgU = 1, OpArgR = 2, OpArgK = 3 }
  8288.  
  8289. ------------------------------------------------------------------------
  8290. -- e.g. to compare with symbols, luaP:getOpMode(...) == luaP.OpCode.iABC
  8291. -- * accepts opcode parameter as strings, e.g. "OP_MOVE"
  8292. ------------------------------------------------------------------------
  8293.  
  8294. function luaP:getOpMode(m)
  8295. return self.opmodes[self.OpCode[m]] % 4
  8296. end
  8297.  
  8298. function luaP:getBMode(m)
  8299. return math.floor(self.opmodes[self.OpCode[m]] / 16) % 4
  8300. end
  8301.  
  8302. function luaP:getCMode(m)
  8303. return math.floor(self.opmodes[self.OpCode[m]] / 4) % 4
  8304. end
  8305.  
  8306. function luaP:testAMode(m)
  8307. return math.floor(self.opmodes[self.OpCode[m]] / 64) % 2
  8308. end
  8309.  
  8310. function luaP:testTMode(m)
  8311. return math.floor(self.opmodes[self.OpCode[m]] / 128)
  8312. end
  8313.  
  8314. -- luaP_opnames[] is set above, as the luaP.opnames table
  8315.  
  8316. -- number of list items to accumulate before a SETLIST instruction
  8317. luaP.LFIELDS_PER_FLUSH = 50
  8318.  
  8319. ------------------------------------------------------------------------
  8320. -- build instruction properties array
  8321. -- * deliberately coded to look like the C equivalent
  8322. ------------------------------------------------------------------------
  8323. local function opmode(t, a, b, c, m)
  8324. local luaP = luaP
  8325. return t * 128 + a * 64 +
  8326. luaP.OpArgMask[b] * 16 + luaP.OpArgMask[c] * 4 + luaP.OpMode[m]
  8327. end
  8328.  
  8329. -- ORDER OP
  8330. luaP.opmodes = {
  8331. -- T A B C mode opcode
  8332. opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_LOADK
  8333. opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_LOADBOOL
  8334. opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LOADNIL
  8335. opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_GETUPVAL
  8336. opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_GETGLOBAL
  8337. opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_GETTABLE
  8338. opmode(0, 0, "OpArgK", "OpArgN", "iABx"), -- OP_SETGLOBAL
  8339. opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_SETUPVAL
  8340. opmode(0, 0, "OpArgK", "OpArgK", "iABC"), -- OP_SETTABLE
  8341. opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_NEWTABLE
  8342. opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_SELF
  8343. opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_ADD
  8344. opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_SUB
  8345. opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MUL
  8346. opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_DIV
  8347. opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MOD
  8348. opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_POW
  8349. opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_UNM
  8350. opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_NOT
  8351. opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LEN
  8352. opmode(0, 1, "OpArgR", "OpArgR", "iABC"), -- OP_CONCAT
  8353. opmode(0, 0, "OpArgR", "OpArgN", "iAsBx"), -- OP_JMP
  8354. opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_EQ
  8355. opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LT
  8356. opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LE
  8357. opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TEST
  8358. opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TESTSET
  8359. opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_CALL
  8360. opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_TAILCALL
  8361. opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_RETURN
  8362. opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORLOOP
  8363. opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORPREP
  8364. opmode(1, 0, "OpArgN", "OpArgU", "iABC"), -- OP_TFORLOOP
  8365. opmode(0, 0, "OpArgU", "OpArgU", "iABC"), -- OP_SETLIST
  8366. opmode(0, 0, "OpArgN", "OpArgN", "iABC"), -- OP_CLOSE
  8367. opmode(0, 1, "OpArgU", "OpArgN", "iABx"), -- OP_CLOSURE
  8368. opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_VARARG
  8369. }
  8370. -- an awkward way to set a zero-indexed table...
  8371. luaP.opmodes[0] =
  8372. opmode(0, 1, "OpArgR", "OpArgN", "iABC") -- OP_MOVE
  8373.  
  8374. return luaP]]></ProtectedString>
  8375. <BinaryString name="Tags"></BinaryString>
  8376. </Properties>
  8377. </Item>
  8378. <Item class="ModuleScript" referent="RBX8B078DFEAA7F44208ECF5696D66AEBB3">
  8379. <Properties>
  8380. <Content name="LinkedSource"><null></null></Content>
  8381. <string name="Name">Rerubi</string>
  8382. <string name="ScriptGuid">{8CDD4A3E-999B-4E2B-ACC4-C871AF954901}</string>
  8383. <ProtectedString name="Source"><![CDATA[local Select = select;
  8384. local Byte = string.byte;
  8385. local Sub = string.sub;
  8386.  
  8387. local Opmode = {
  8388. {b = 'OpArgR', c='OpArgN'}, {b = 'OpArgK', c='OpArgN'}, {b = 'OpArgU', c='OpArgU'},
  8389. {b = 'OpArgR', c='OpArgN'}, {b = 'OpArgU', c='OpArgN'}, {b = 'OpArgK', c='OpArgN'},
  8390. {b = 'OpArgR', c='OpArgK'}, {b = 'OpArgK', c='OpArgN'}, {b = 'OpArgU', c='OpArgN'},
  8391. {b = 'OpArgK', c='OpArgK'}, {b = 'OpArgU', c='OpArgU'}, {b = 'OpArgR', c='OpArgK'},
  8392. {b = 'OpArgK', c='OpArgK'}, {b = 'OpArgK', c='OpArgK'}, {b = 'OpArgK', c='OpArgK'},
  8393. {b = 'OpArgK', c='OpArgK'}, {b = 'OpArgK', c='OpArgK'}, {b = 'OpArgK', c='OpArgK'},
  8394. {b = 'OpArgR', c='OpArgN'}, {b = 'OpArgR', c='OpArgN'}, {b = 'OpArgR', c='OpArgN'},
  8395. {b = 'OpArgR', c='OpArgR'}, {b = 'OpArgR', c='OpArgN'}, {b = 'OpArgK', c='OpArgK'},
  8396. {b = 'OpArgK', c='OpArgK'}, {b = 'OpArgK', c='OpArgK'}, {b = 'OpArgR', c='OpArgU'},
  8397. {b = 'OpArgR', c='OpArgU'}, {b = 'OpArgU', c='OpArgU'}, {b = 'OpArgU', c='OpArgU'},
  8398. {b = 'OpArgU', c='OpArgN'}, {b = 'OpArgR', c='OpArgN'}, {b = 'OpArgR', c='OpArgN'},
  8399. {b = 'OpArgN', c='OpArgU'}, {b = 'OpArgU', c='OpArgU'}, {b = 'OpArgN', c='OpArgN'},
  8400. {b = 'OpArgU', c='OpArgN'}, {b = 'OpArgU', c='OpArgN'}
  8401. };
  8402.  
  8403. local Opcode = { -- Opcode types.
  8404. 'ABC', 'ABx', 'ABC', 'ABC';
  8405. 'ABC', 'ABx', 'ABC', 'ABx';
  8406. 'ABC', 'ABC', 'ABC', 'ABC';
  8407. 'ABC', 'ABC', 'ABC', 'ABC';
  8408. 'ABC', 'ABC', 'ABC', 'ABC';
  8409. 'ABC', 'ABC', 'AsBx', 'ABC';
  8410. 'ABC', 'ABC', 'ABC', 'ABC';
  8411. 'ABC', 'ABC', 'ABC', 'AsBx';
  8412. 'AsBx', 'ABC', 'ABC', 'ABC';
  8413. 'ABx', 'ABC';
  8414. };
  8415.  
  8416. -- rlbi author -> Rerumu
  8417. -- special thanks;
  8418. -- @cntkillme for providing faster bit extraction
  8419. -- @Eternal for being #1 bug finder and providing better float decoder
  8420. -- @stravant for contributing to the original project this is derived from
  8421.  
  8422. -- rerubi is an upgrade to the original Lua VM in Lua
  8423. -- the prime goal of rerubi is to be the fastest:tm: alternative
  8424. -- to a Lua in Lua bytecode execution
  8425.  
  8426. local function gBit(Bit, Start, End) -- No tail-calls, yay.
  8427. if End then -- Thanks to cntkillme for giving input on this shorter, better approach.
  8428. local Res = (Bit / 2 ^ (Start - 1)) % 2 ^ ((End - 1) - (Start - 1) + 1);
  8429.  
  8430. return Res - Res % 1;
  8431. else
  8432. local Plc = 2 ^ (Start - 1);
  8433.  
  8434. if (Bit % (Plc + Plc) >= Plc) then
  8435. return 1;
  8436. else
  8437. return 0;
  8438. end;
  8439. end;
  8440. end;
  8441.  
  8442. local function GetMeaning(ByteString)
  8443. local Pos = 1;
  8444. local gSizet;
  8445. local gInt;
  8446.  
  8447. local function gBits8() -- Get the next byte in the stream.
  8448. local F = Byte(ByteString, Pos, Pos);
  8449.  
  8450. Pos = Pos + 1;
  8451.  
  8452. return F;
  8453. end;
  8454.  
  8455. local function gBits32()
  8456. local W, X, Y, Z = Byte(ByteString, Pos, Pos + 3);
  8457.  
  8458. Pos = Pos + 4;
  8459.  
  8460. return (Z * 16777216) + (Y * 65536) + (X * 256) + W;
  8461. end;
  8462.  
  8463. local function gBits64()
  8464. return gBits32() * 4294967296 + gBits32();
  8465. end;
  8466.  
  8467. local function gFloat()
  8468. -- thanks @Eternal for giving me this so I could mangle it in here and have it work
  8469. local Left = gBits32();
  8470. local Right = gBits32();
  8471. local IsNormal = 1
  8472. local Mantissa = (gBit(Right, 1, 20) * (2 ^ 32))
  8473. + Left;
  8474.  
  8475. local Exponent = gBit(Right, 21, 31);
  8476. local Sign = ((-1) ^ gBit(Right, 32));
  8477.  
  8478. if (Exponent == 0) then
  8479. if (Mantissa == 0) then
  8480. return Sign * 0 -- +-0
  8481. else
  8482. Exponent = 1
  8483. IsNormal = 0
  8484. end
  8485. elseif (Exponent == 2047) then
  8486. if (Mantissa == 0) then
  8487. return Sign * (1 / 0) -- +-Inf
  8488. else
  8489. return Sign * (0 / 0) -- +-Q/Nan
  8490. end
  8491. end
  8492.  
  8493. -- sign * 2**e-1023 * isNormal.mantissa
  8494. return math.ldexp(Sign, Exponent - 1023) * (IsNormal + (Mantissa / (2 ^ 52)))
  8495. end;
  8496.  
  8497. local function gString(Len)
  8498. local Str;
  8499.  
  8500. if Len then
  8501. Str = Sub(ByteString, Pos, Pos + Len - 1);
  8502.  
  8503. Pos = Pos + Len;
  8504. else
  8505. Len = gSizet();
  8506.  
  8507. if (Len == 0) then return; end;
  8508.  
  8509. Str = Sub(ByteString, Pos, Pos + Len - 1);
  8510.  
  8511. Pos = Pos + Len;
  8512. end;
  8513.  
  8514. return Str;
  8515. end;
  8516.  
  8517. local function ChunkDecode()
  8518. local Instr = {};
  8519. local Const = {};
  8520. local Proto = {};
  8521. local Chunk = {
  8522. Instr = Instr; -- Instructions
  8523. Const = Const; -- Constants
  8524. Proto = Proto; -- Prototypes
  8525. Lines = {}; -- Lines
  8526. Name = gString(); -- Grab name string.
  8527. FirstL = gInt(); -- First line.
  8528. LastL = gInt(); -- Last line.
  8529. Upvals = gBits8(); -- Upvalue count.
  8530. Args = gBits8(); -- Arg count.
  8531. Vargs = gBits8(); -- Vararg type.
  8532. Stack = gBits8(); -- Stack.
  8533. };
  8534. local ConstantReferences = {}; -- for an optimization
  8535.  
  8536. if Chunk.Name then
  8537. Chunk.Name = Sub(Chunk.Name, 1, -2);
  8538. end;
  8539.  
  8540.  
  8541. for Idx = 1, gInt() do -- Loading instructions to the chunk.
  8542. local Data = gBits32();
  8543. local Opco = gBit(Data, 1, 6);
  8544. local Type = Opcode[Opco + 1];
  8545. local Mode = Opmode[Opco + 1];
  8546.  
  8547. local Inst = {
  8548. Enum = Opco;
  8549. Value = Data;
  8550. gBit(Data, 7, 14); -- Register A.
  8551. };
  8552.  
  8553. if (Type == 'ABC') then -- Most common, basic instruction type.
  8554. Inst[2] = gBit(Data, 24, 32);
  8555. Inst[3] = gBit(Data, 15, 23);
  8556. elseif (Type == 'ABx') then
  8557. Inst[2] = gBit(Data, 15, 32);
  8558. elseif (Type == 'AsBx') then
  8559. Inst[2] = gBit(Data, 15, 32) - 131071;
  8560. end;
  8561.  
  8562. -- Precompute data for some instructions
  8563. do
  8564. -- TEST and TESTSET
  8565. if Opco == 26 or Opco == 27 then
  8566. Inst[3] = Inst[3] == 0;
  8567. end
  8568.  
  8569. -- EQ, LT, LE
  8570. if Opco >= 23 and Opco <= 25 then
  8571. Inst[1] = Inst[1] ~= 0;
  8572. end
  8573.  
  8574. -- Anything that looks at a constant using B
  8575. if Mode.b == 'OpArgK' then
  8576. Inst[3] = Inst[3] or false; -- Simply to guarantee that Inst[4] is inserted in the array part
  8577. if Inst[2] >= 256 then
  8578. local Cons = Inst[2] - 256;
  8579. Inst[4] = Cons;
  8580.  
  8581. local ReferenceData = ConstantReferences[Cons];
  8582. if not ReferenceData then
  8583. ReferenceData = {};
  8584. ConstantReferences[Cons] = ReferenceData;
  8585. end
  8586.  
  8587. ReferenceData[#ReferenceData + 1] = {Inst = Inst, Register = 4}
  8588. end
  8589. end
  8590.  
  8591. -- Anything that looks at a constant using C
  8592. if Mode.c == 'OpArgK' then
  8593. Inst[4] = Inst[4] or false -- Simply to guarantee that Inst[5] is inserted in the array part
  8594. if Inst[3] >= 256 then
  8595. local Cons = Inst[3] - 256;
  8596. Inst[5] = Cons;
  8597.  
  8598. local ReferenceData = ConstantReferences[Cons];
  8599. if not ReferenceData then
  8600. ReferenceData = {};
  8601. ConstantReferences[Cons] = ReferenceData;
  8602. end
  8603.  
  8604. ReferenceData[#ReferenceData + 1] = {Inst = Inst, Register = 5}
  8605. end
  8606. end
  8607. end
  8608.  
  8609. Instr[Idx] = Inst;
  8610. end;
  8611.  
  8612. for Idx = 1, gInt() do -- Load constants.
  8613. local Type = gBits8();
  8614. local Cons;
  8615.  
  8616. if (Type == 1) then -- Boolean
  8617. Cons = (gBits8() ~= 0);
  8618. elseif (Type == 3) then -- Float/Double
  8619. Cons = gFloat();
  8620. elseif (Type == 4) then
  8621. Cons = Sub(gString(), 1, -2);
  8622. end;
  8623.  
  8624. -- Finish precomputing constants
  8625. local Refs = ConstantReferences[Idx - 1];
  8626. if Refs then
  8627. for i = 1, #Refs do
  8628. Refs[i].Inst[Refs[i].Register] = Cons
  8629. end
  8630. end
  8631.  
  8632. -- Write Constant to pool
  8633. Const[Idx - 1] = Cons;
  8634. end;
  8635.  
  8636. for Idx = 1, gInt() do -- Nested function prototypes.
  8637. Proto[Idx - 1] = ChunkDecode();
  8638. end;
  8639.  
  8640. do -- Debugging
  8641. local Lines = Chunk.Lines;
  8642.  
  8643. for Idx = 1, gInt() do
  8644. Lines[Idx] = gBits32();
  8645. end;
  8646.  
  8647. for _ = 1, gInt() do -- Locals in stack.
  8648. gString(); -- Name of local.
  8649. gBits32(); -- Starting point.
  8650. gBits32(); -- End point.
  8651. end;
  8652.  
  8653. for _ = 1, gInt() do -- Upvalues.
  8654. gString(); -- Name of upvalue.
  8655. end;
  8656. end;
  8657.  
  8658. return Chunk; -- Finished chunk.
  8659. end;
  8660.  
  8661. do -- Most of this chunk I was too lazy to reformat or change
  8662. assert(gString(4) == "\27Lua", "Lua bytecode expected.");
  8663. assert(gBits8() == 0x51, "Only Lua 5.1 is supported.");
  8664.  
  8665. gBits8(); -- Probably version control.
  8666. gBits8(); -- Is small endians.
  8667.  
  8668. local IntSize = gBits8(); -- Int size
  8669. local Sizet = gBits8(); -- size_t
  8670.  
  8671. if (IntSize == 4) then
  8672. gInt = gBits32;
  8673. elseif (IntSize == 8) then
  8674. gInt = gBits64;
  8675. else
  8676. error('Integer size not supported', 2);
  8677. end;
  8678.  
  8679. if (Sizet == 4) then
  8680. gSizet = gBits32;
  8681. elseif (Sizet == 8) then
  8682. gSizet = gBits64;
  8683. else
  8684. error('Sizet size not supported', 2);
  8685. end;
  8686.  
  8687. assert(gString(3) == "\4\8\0", "Unsupported bytecode target platform");
  8688. end;
  8689.  
  8690. return ChunkDecode();
  8691. end;
  8692.  
  8693. local function _Returns(...)
  8694. return Select('#', ...), {...};
  8695. end;
  8696.  
  8697. local function Wrap(Chunk, Env, Upvalues)
  8698. local Instr = Chunk.Instr;
  8699. local Const = Chunk.Const;
  8700. local Proto = Chunk.Proto;
  8701.  
  8702. local function OnError(Err, Position) -- Handle your errors in whatever way.
  8703. local Name = Chunk.Name or 'Code';
  8704. local Line = Chunk.Lines[Position] or '?';
  8705.  
  8706. error(string.format('%s:%s: %s', Name, Line, tostring(Err)), 0);
  8707. end;
  8708.  
  8709. return function(...)
  8710. -- Returned function to run bytecode chunk (Don't be stupid, you can't setfenv this to work your way).
  8711. local InstrPoint, Top = 1, -1;
  8712. local Vararg, Varargsz = {}, Select('#', ...) - 1;
  8713.  
  8714. local GStack = {};
  8715. local Lupvals = {};
  8716. local Stack = setmetatable({}, {
  8717. __index = GStack;
  8718. __newindex = function(_, Key, Value)
  8719. if (Key > Top) then
  8720. Top = Key;
  8721. end;
  8722.  
  8723. GStack[Key] = Value;
  8724. end;
  8725. });
  8726.  
  8727. local function Loop()
  8728. local Inst, Enum;
  8729.  
  8730. while true do
  8731. Inst = Instr[InstrPoint];
  8732. Enum = Inst.Enum;
  8733. InstrPoint = InstrPoint + 1;
  8734.  
  8735. if (Enum == 0) then -- MOVE
  8736. Stack[Inst[1]] = Stack[Inst[2]];
  8737. elseif (Enum == 1) then -- LOADK
  8738. Stack[Inst[1]] = Const[Inst[2]];
  8739. elseif (Enum == 2) then -- LOADBOOL
  8740. Stack[Inst[1]] = (Inst[2] ~= 0);
  8741.  
  8742. if (Inst[3] ~= 0) then
  8743. InstrPoint = InstrPoint + 1;
  8744. end;
  8745. elseif (Enum == 3) then -- LOADNIL
  8746. local Stk = Stack;
  8747.  
  8748. for Idx = Inst[1], Inst[2] do
  8749. Stk[Idx] = nil;
  8750. end;
  8751. elseif (Enum == 4) then -- GETUPVAL
  8752. Stack[Inst[1]] = Upvalues[Inst[2]];
  8753. elseif (Enum == 5) then -- GETGLOBAL
  8754. Stack[Inst[1]] = Env[Const[Inst[2]]];
  8755. elseif (Enum == 6) then -- GETTABLE
  8756. local Stk = Stack;
  8757. Stk[Inst[1]] = Stk[Inst[2]][Inst[5] or Stk[Inst[3]]];
  8758. elseif (Enum == 7) then -- SETGLOBAL
  8759. Env[Const[Inst[2]]] = Stack[Inst[1]];
  8760. elseif (Enum == 8) then -- SETUPVAL
  8761. Upvalues[Inst[2]] = Stack[Inst[1]];
  8762. elseif (Enum == 9) then -- SETTABLE
  8763. local Stk = Stack
  8764. Stk[Inst[1]][Inst[4] or Stk[Inst[2]]] = Inst[5] or Stk[Inst[3]]
  8765. elseif (Enum == 10) then -- NEWTABLE
  8766. Stack[Inst[1]] = {};
  8767. elseif (Enum == 11) then -- SELF
  8768. local Stk = Stack;
  8769. local A = Inst[1];
  8770. local B = Stk[Inst[2]];
  8771. local C = Inst[5] or Stk[Inst[3]];
  8772. Stk[A + 1] = B;
  8773. Stk[A] = B[C];
  8774. elseif (Enum == 12) then -- ADD
  8775. local Stk = Stack;
  8776. Stk[Inst[1]] = (Inst[4] or Stk[Inst[2]]) + (Inst[5] or Stk[Inst[3]]);
  8777. elseif (Enum == 13) then -- SUB
  8778. local Stk = Stack;
  8779. Stk[Inst[1]] = (Inst[4] or Stk[Inst[2]]) - (Inst[5] or Stk[Inst[3]]);
  8780. elseif (Enum == 14) then -- MUL
  8781. local Stk = Stack;
  8782. Stk[Inst[1]] = (Inst[4] or Stk[Inst[2]]) * (Inst[5] or Stk[Inst[3]]);
  8783. elseif (Enum == 15) then -- DIV
  8784. local Stk = Stack;
  8785. Stk[Inst[1]] = (Inst[4] or Stk[Inst[2]]) / (Inst[5] or Stk[Inst[3]]);
  8786. elseif (Enum == 16) then -- MOD
  8787. local Stk = Stack;
  8788. Stk[Inst[1]] = (Inst[4] or Stk[Inst[2]]) % (Inst[5] or Stk[Inst[3]]);
  8789. elseif (Enum == 17) then -- POW
  8790. local Stk = Stack;
  8791. Stk[Inst[1]] = (Inst[4] or Stk[Inst[2]]) ^ (Inst[5] or Stk[Inst[3]]);
  8792. elseif (Enum == 18) then -- UNM
  8793. Stack[Inst[1]] = -Stack[Inst[2]];
  8794. elseif (Enum == 19) then -- NOT
  8795. Stack[Inst[1]] = (not Stack[Inst[2]]);
  8796. elseif (Enum == 20) then -- LEN
  8797. Stack[Inst[1]] = #Stack[Inst[2]];
  8798. elseif (Enum == 21) then -- CONCAT
  8799. local Stk = Stack;
  8800. local B = Inst[2];
  8801. local K = Stk[B];
  8802.  
  8803. for Idx = B + 1, Inst[3] do
  8804. K = K .. Stk[Idx];
  8805. end;
  8806.  
  8807. Stack[Inst[1]] = K;
  8808. elseif (Enum == 22) then -- JMP
  8809. InstrPoint = InstrPoint + Inst[2];
  8810. elseif (Enum == 23) then -- EQ
  8811. local Stk = Stack;
  8812. local B = Inst[4] or Stk[Inst[2]];
  8813. local C = Inst[5] or Stk[Inst[3]];
  8814.  
  8815. if (B == C) ~= Inst[1] then
  8816. InstrPoint = InstrPoint + 1;
  8817. end;
  8818. elseif (Enum == 24) then -- LT
  8819. local Stk = Stack;
  8820. local B = Inst[4] or Stk[Inst[2]];
  8821. local C = Inst[5] or Stk[Inst[3]];
  8822.  
  8823. if (B < C) ~= Inst[1] then
  8824. InstrPoint = InstrPoint + 1;
  8825. end;
  8826. elseif (Enum == 25) then -- LE
  8827. local Stk = Stack;
  8828. local B = Inst[4] or Stk[Inst[2]];
  8829. local C = Inst[5] or Stk[Inst[3]];
  8830.  
  8831. if (B <= C) ~= Inst[1] then
  8832. InstrPoint = InstrPoint + 1;
  8833. end;
  8834. elseif (Enum == 26) then -- TEST
  8835. if Inst[3] then
  8836. if Stack[Inst[1]] then
  8837. InstrPoint = InstrPoint + 1;
  8838. end
  8839. elseif Stack[Inst[1]] then
  8840. else
  8841. InstrPoint = InstrPoint + 1;
  8842. end
  8843. elseif (Enum == 27) then -- TESTSET
  8844. local B = Stack[Inst[2]];
  8845.  
  8846. if Inst[3] then
  8847. if B then
  8848. InstrPoint = InstrPoint + 1;
  8849. else
  8850. Stack[Inst[1]] = B
  8851. end
  8852. elseif B then
  8853. Stack[Inst[1]] = B
  8854. else
  8855. InstrPoint = InstrPoint + 1;
  8856. end
  8857. elseif (Enum == 28) then -- CALL
  8858. local A = Inst[1];
  8859. local B = Inst[2];
  8860. local C = Inst[3];
  8861. local Stk = Stack;
  8862. local Args, Results;
  8863. local Limit, Edx;
  8864.  
  8865. Args = {};
  8866.  
  8867. if (B ~= 1) then
  8868. if (B ~= 0) then
  8869. Limit = A + B - 1;
  8870. else
  8871. Limit = Top;
  8872. end;
  8873.  
  8874. Edx = 0;
  8875.  
  8876. for Idx = A + 1, Limit do
  8877. Edx = Edx + 1;
  8878.  
  8879. Args[Edx] = Stk[Idx];
  8880. end;
  8881.  
  8882. Limit, Results = _Returns(Stk[A](unpack(Args, 1, Limit - A)));
  8883. else
  8884. Limit, Results = _Returns(Stk[A]());
  8885. end;
  8886.  
  8887. Top = A - 1;
  8888.  
  8889. if (C ~= 1) then
  8890. if (C ~= 0) then
  8891. Limit = A + C - 2;
  8892. else
  8893. Limit = Limit + A - 1;
  8894. end;
  8895.  
  8896. Edx = 0;
  8897.  
  8898. for Idx = A, Limit do
  8899. Edx = Edx + 1;
  8900.  
  8901. Stk[Idx] = Results[Edx];
  8902. end;
  8903. end;
  8904. elseif (Enum == 29) then -- TAILCALL
  8905. local A = Inst[1];
  8906. local B = Inst[2];
  8907. local Stk = Stack;
  8908. local Args, Results;
  8909. local Limit;
  8910. local Rets = 0;
  8911.  
  8912. Args = {};
  8913.  
  8914. if (B ~= 1) then
  8915. if (B ~= 0) then
  8916. Limit = A + B - 1;
  8917. else
  8918. Limit = Top;
  8919. end
  8920.  
  8921. for Idx = A + 1, Limit do
  8922. Args[#Args + 1] = Stk[Idx];
  8923. end
  8924.  
  8925. Results = {Stk[A](unpack(Args, 1, Limit - A))};
  8926. else
  8927. Results = {Stk[A]()};
  8928. end;
  8929.  
  8930. for Index in pairs(Results) do -- get return count
  8931. if (Index > Rets) then
  8932. Rets = Index;
  8933. end;
  8934. end;
  8935.  
  8936. return Results, Rets;
  8937. elseif (Enum == 30) then -- RETURN
  8938. local A = Inst[1];
  8939. local B = Inst[2];
  8940. local Stk = Stack;
  8941. local Edx, Output;
  8942. local Limit;
  8943.  
  8944. if (B == 1) then
  8945. return;
  8946. elseif (B == 0) then
  8947. Limit = Top;
  8948. else
  8949. Limit = A + B - 2;
  8950. end;
  8951.  
  8952. Output = {};
  8953. Edx = 0;
  8954.  
  8955. for Idx = A, Limit do
  8956. Edx = Edx + 1;
  8957.  
  8958. Output[Edx] = Stk[Idx];
  8959. end;
  8960.  
  8961. return Output, Edx;
  8962. elseif (Enum == 31) then -- FORLOOP
  8963. local A = Inst[1];
  8964. local Stk = Stack;
  8965.  
  8966. local Step = Stk[A + 2];
  8967. local Index = Stk[A] + Step;
  8968.  
  8969. Stk[A] = Index;
  8970.  
  8971. if (Step > 0) then
  8972. if Index <= Stk[A + 1] then
  8973. InstrPoint = InstrPoint + Inst[2];
  8974.  
  8975. Stk[A + 3] = Index;
  8976. end;
  8977. else
  8978. if Index >= Stk[A + 1] then
  8979. InstrPoint = InstrPoint + Inst[2];
  8980.  
  8981. Stk[A + 3] = Index;
  8982. end
  8983. end
  8984. elseif (Enum == 32) then -- FORPREP
  8985. local A = Inst[1];
  8986. local Stk = Stack;
  8987.  
  8988. -- As per mirroring the real vm
  8989. Stk[A] = assert(tonumber(Stk[A]), '`for` initial value must be a number');
  8990. Stk[A + 1] = assert(tonumber(Stk[A + 1]), '`for` limit must be a number');
  8991. Stk[A + 2] = assert(tonumber(Stk[A + 2]), '`for` step must be a number');
  8992.  
  8993. Stk[A] = Stk[A] - Stk[A + 2];
  8994.  
  8995. InstrPoint = InstrPoint + Inst[2];
  8996. elseif (Enum == 33) then -- TFORLOOP
  8997. local A = Inst[1];
  8998. local C = Inst[3];
  8999. local Stk = Stack;
  9000.  
  9001. local Offset = A + 2;
  9002. local Result = {Stk[A](Stk[A + 1], Stk[A + 2])};
  9003.  
  9004. for Idx = 1, C do
  9005. Stack[Offset + Idx] = Result[Idx];
  9006. end;
  9007.  
  9008. if (Stk[A + 3] ~= nil) then
  9009. Stk[A + 2] = Stk[A + 3];
  9010. else
  9011. InstrPoint = InstrPoint + 1;
  9012. end;
  9013. elseif (Enum == 34) then -- SETLIST
  9014. local A = Inst[1];
  9015. local B = Inst[2];
  9016. local C = Inst[3];
  9017. local Stk = Stack;
  9018.  
  9019. if (C == 0) then
  9020. InstrPoint = InstrPoint + 1;
  9021. C = Instr[InstrPoint].Value;
  9022. end;
  9023.  
  9024. local Offset = (C - 1) * 50;
  9025. local T = Stk[A]; -- Assuming T is the newly created table.
  9026.  
  9027. if (B == 0) then
  9028. B = Top - A;
  9029. end;
  9030.  
  9031. for Idx = 1, B do
  9032. T[Offset + Idx] = Stk[A + Idx];
  9033. end;
  9034. elseif (Enum == 35) then -- CLOSE
  9035. local A = Inst[1];
  9036. local Cls = {}; -- Slight doubts on any issues this may cause
  9037.  
  9038. for Idx = 1, #Lupvals do
  9039. local List = Lupvals[Idx];
  9040.  
  9041. for Idz = 0, #List do
  9042. local Upv = List[Idz];
  9043. local Stk = Upv[1];
  9044. local Pos = Upv[2];
  9045.  
  9046. if (Stk == Stack) and (Pos >= A) then
  9047. Cls[Pos] = Stk[Pos];
  9048. Upv[1] = Cls; -- @memcorrupt credit me for the spoonfeed
  9049. end;
  9050. end;
  9051. end;
  9052. elseif (Enum == 36) then -- CLOSURE
  9053. local NewProto = Proto[Inst[2]];
  9054. local Stk = Stack;
  9055.  
  9056. local Indexes;
  9057. local NewUvals;
  9058.  
  9059. if (NewProto.Upvals ~= 0) then
  9060. Indexes = {};
  9061. NewUvals = setmetatable({}, {
  9062. __index = function(_, Key)
  9063. local Val = Indexes[Key];
  9064.  
  9065. return Val[1][Val[2]];
  9066. end,
  9067. __newindex = function(_, Key, Value)
  9068. local Val = Indexes[Key];
  9069.  
  9070. Val[1][Val[2]] = Value;
  9071. end;
  9072. }
  9073. );
  9074.  
  9075. for Idx = 1, NewProto.Upvals do
  9076. local Mvm = Instr[InstrPoint];
  9077.  
  9078. if (Mvm.Enum == 0) then -- MOVE
  9079. Indexes[Idx - 1] = {Stk, Mvm[2]};
  9080. elseif (Mvm.Enum == 4) then -- GETUPVAL
  9081. Indexes[Idx - 1] = {Upvalues, Mvm[2]};
  9082. end;
  9083.  
  9084. InstrPoint = InstrPoint + 1;
  9085. end;
  9086.  
  9087. Lupvals[#Lupvals + 1] = Indexes;
  9088. end;
  9089.  
  9090. Stk[Inst[1]] = Wrap(NewProto, Env, NewUvals);
  9091. elseif (Enum == 37) then -- VARARG
  9092. local A = Inst[1];
  9093. local B = Inst[2];
  9094. local Stk, Vars = Stack, Vararg;
  9095.  
  9096. Top = A - 1;
  9097.  
  9098. for Idx = A, A + (B > 0 and B - 1 or Varargsz) do
  9099. Stk[Idx] = Vars[Idx - A];
  9100. end;
  9101. end;
  9102. end;
  9103. end;
  9104.  
  9105. local Args = {...};
  9106.  
  9107. for Idx = 0, Varargsz do
  9108. if (Idx >= Chunk.Args) then
  9109. Vararg[Idx - Chunk.Args] = Args[Idx + 1];
  9110. else
  9111. Stack[Idx] = Args[Idx + 1];
  9112. end;
  9113. end;
  9114.  
  9115. local A, B, C = pcall(Loop); -- Pcalling to allow yielding
  9116.  
  9117. if A then -- We're always expecting this to come out true (because errorless code)
  9118. if B and (C > 0) then -- So I flipped the conditions.
  9119. return unpack(B, 1, C);
  9120. end;
  9121.  
  9122. return;
  9123. else
  9124. OnError(B, InstrPoint - 1); -- Didn't get time to test the `-1` honestly, but I assume it works properly
  9125. end;
  9126. end;
  9127. end;
  9128.  
  9129. return function(BCode, Env) -- lua_function LoadBytecode (string BCode, table Env)
  9130. local Buffer = GetMeaning(BCode);
  9131.  
  9132. return Wrap(Buffer, Env or getfenv(0)), Buffer;
  9133. end;
  9134. ]]></ProtectedString>
  9135. <BinaryString name="Tags"></BinaryString>
  9136. </Properties>
  9137. </Item>
  9138. <Item class="Script" referent="RBX9BAAC995A4854EFCBB2D1DFE3A152236">
  9139. <Properties>
  9140. <bool name="Disabled">true</bool>
  9141. <Content name="LinkedSource"><null></null></Content>
  9142. <string name="Name">Credits</string>
  9143. <string name="ScriptGuid">{4B480C1C-A37C-41F3-BE92-D3386E3ACBD8}</string>
  9144. <ProtectedString name="Source"><![CDATA[--[[
  9145. LuLu 5.1 VM (original implementation) - http://lulu.luaforge.net/
  9146. * Rerubu (rewrite based off LuLu) - https://github.com/Rerumu/Rerubi
  9147. Yueliang 5 (Lua compiler in Lua) - http://yueliang.luaforge.net/
  9148. * einsteinK: various bug fixes
  9149. ]]]]></ProtectedString>
  9150. <BinaryString name="Tags"></BinaryString>
  9151. </Properties>
  9152. </Item>
  9153. </Item>
  9154. </Item>
  9155. </roblox>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement