Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local STRING_BORDERS = {"'", '"', "*", "+", "$", "#", "@", "!", "^", "_"}
- local STRING_BORDERS_MAP = {}
- local SHOULD_BE_REPLACED_KEY = {}
- for _, v in STRING_BORDERS do
- STRING_BORDERS_MAP[v] = true
- end
- local Parser = {}
- Parser.__index = Parser
- function Parser.new(text, index)
- local self = setmetatable({}, Parser)
- self.Text = text
- self.Index = index or 1
- return self
- end
- function Parser:GetNextCharacter()
- local letter = self.Text:sub(self.Index, self.Index)
- self.Index += #letter
- return letter
- end
- function Parser:GetNextNumber()
- local hasFoundDot = false
- local copy = self:Copy()
- local text = self:GetNextSolidCharacter()
- while self:IsActive() do
- local copy = self:Copy()
- local digit = copy:GetNextCharacter()
- if digit == "." then
- if hasFoundDot then
- break
- end
- hasFoundDot = true
- elseif not tonumber(digit) then
- break
- end
- self:Apply(copy)
- text = text..digit
- end
- local number = tonumber(text)
- if not number then
- return nil
- end
- return number
- end
- function Parser:GetNextSolidCharacter()
- local nextChar repeat
- nextChar = self:GetNextCharacter()
- until nextChar ~= " " and nextChar ~= "\n" and nextChar ~= "\t"
- return nextChar
- end
- function Parser:GetTextLeftUntilE(stops)
- local map = {}
- for _, v in stops do
- map[v] = true
- end
- local text = ""
- while self:IsActive() do
- local char = self:GetNextCharacter()
- if map[char] then
- break
- end
- text ..= char
- end
- return text
- end
- function Parser:GetTextLeftUntil(stop)
- return self:GetTextLeftUntilE({stop})
- end
- function Parser:GetTextLeft()
- return self:GetTextLeftUntil()
- end
- function Parser:GetNextWord()
- local word = ""
- while self:IsActive() and word == "" do
- word = self:GetTextLeftUntilE({"\t", "\n", " "})
- end
- return word
- end
- function Parser:GetWordsLeft()
- local words = {}
- while not self:HasFinished() do
- local word = self:GetNextWord()
- if word == "" then
- break
- end
- table.insert(words, word)
- end
- return words
- end
- function Parser:HasFinished()
- return self.Index > #self.Text
- end
- function Parser:IsActive()
- return not self:HasFinished()
- end
- function Parser:Copy()
- return Parser.new(self.Text, self.Index)
- end
- function Parser:Apply(parser)
- self.Text = parser.Text
- self.Index = parser.Index
- end
- local function convertTableToString(main)
- local result = ""
- local nameMap = {}
- local tables = {}
- local nextName = 1
- local function addToNameMap(tbl)
- if nameMap[tbl] then
- return
- end
- table.insert(tables, tbl)
- nameMap[tbl] = nextName
- nextName += 1
- local metatable = getmetatable(tbl)
- if metatable then
- addToNameMap(metatable)
- end
- for k, v in tbl do
- if type(k) == "table" then
- addToNameMap(k)
- end
- if type(v) == "table" then
- addToNameMap(v)
- end
- end
- end
- local function convertItem(item)
- local itemType = type(item)
- if itemType == "string" then
- local border
- for _, possibleBorder in STRING_BORDERS do
- if not item:find(possibleBorder) then
- border = possibleBorder
- break
- end
- end
- if not border then
- error("The string you've entered has all the possible borders")
- end
- return border..item..border
- end
- return
- if itemType == "number" then tostring(item)
- elseif itemType == "boolean" then (item and "true" or "false")
- elseif itemType == "table" then `i {nameMap[item]}`
- else error("invalid item type "..itemType)
- end
- addToNameMap(main)
- for name, tbl in tables do
- local stringTbl = ""
- for k, v in tbl do
- local stringKey = convertItem(k)
- local stringValue = convertItem(v)
- stringTbl ..= `\t[{stringKey}] {stringValue};\n`
- end
- stringTbl = string.format("{\n%s}", stringTbl)
- local metatable = getmetatable(tbl)
- if metatable then
- stringTbl = `{stringTbl} m {convertItem(metatable)}`
- end
- stringTbl ..= "\n"
- result ..= stringTbl
- end
- return result
- end
- local function getNextItem(parser)
- local oldParser = parser:Copy()
- local nextChar = parser:GetNextSolidCharacter()
- if STRING_BORDERS_MAP[nextChar] then
- return parser:GetTextLeftUntil(nextChar)
- end
- if nextChar == "i" then
- local name = parser:GetNextNumber()
- if not name or math.floor(name) ~= name then
- error("the table name given is not an integer")
- end
- return {
- [SHOULD_BE_REPLACED_KEY] = true,
- Name = name,
- }
- end
- if nextChar == "{" then
- local tbl = {}
- while parser:IsActive() do
- local copy = parser:Copy()
- if copy:GetNextSolidCharacter() ~= "[" then
- break
- end
- parser:Apply(copy)
- local key = getNextItem(parser)
- if parser:GetNextSolidCharacter() ~= "]" then
- error("given unexpected content to a key")
- end
- local value = getNextItem(parser)
- if parser:GetNextSolidCharacter() ~= ";" then
- print("VALUE", value)
- error("given unexpected content to a value")
- end
- tbl[key] = value
- end
- if parser:HasFinished() then
- error("table never ended")
- end
- local nextCharacter = parser:GetNextSolidCharacter()
- if nextCharacter ~= "}" then
- error("given unexcepted content to a table")
- end
- local copy = parser:Copy()
- local word = copy:GetNextWord()
- if word == "m" then
- local metatable = getNextItem(copy)
- if type(metatable) ~= "table" then
- error("invalid metatable type")
- end
- setmetatable(tbl, metatable)
- parser:Apply(copy)
- end
- return tbl
- end
- parser:Apply(oldParser)
- local number = parser:GetNextNumber()
- if number then
- return number
- end
- parser:Apply(oldParser)
- local word = parser:GetNextSolidCharacter()..parser:GetTextLeftUntil("e").."e"
- if word == "true" then
- return true
- end
- if word == "false" then
- return false
- end
- error("invalid input given")
- end
- local function convertStringToTable(str)
- local parser = Parser.new(str)
- local items = {}
- while true do
- local copy = parser:Copy()
- if copy:GetNextSolidCharacter() == "" then
- break
- end
- local item = getNextItem(parser)
- table.insert(items, item)
- end
- local function validateItemName(name)
- local item = items[name]
- if item == nil then
- error("invalid item name given")
- end
- return item
- end
- local loopedThrough = {}
- local function forEachTable(tbl)
- if loopedThrough[tbl] then
- return
- end
- loopedThrough[tbl] = true
- for k, v in tbl do
- if type(k) == "table" and k[SHOULD_BE_REPLACED_KEY] then
- tbl[validateItemName(k.Name)] = v
- tbl[k] = nil
- end
- end
- for k, v in tbl do
- if type(v) == "table" and v[SHOULD_BE_REPLACED_KEY] then
- tbl[k] = validateItemName(v.Name)
- end
- end
- local metatable = getmetatable(tbl)
- if metatable and metatable[SHOULD_BE_REPLACED_KEY] then
- local newMetatable = validateItemName(metatable.Name)
- if type(newMetatable) ~= "table" then
- error("invalid metatable type")
- end
- setmetatable(tbl, newMetatable)
- end
- for k, v in tbl do
- if type(k) == "table" then
- forEachTable(k)
- end
- if type(v) == "table" then
- forEachTable(v)
- end
- end
- local metatable = getmetatable(tbl)
- if metatable then
- forEachTable(metatable)
- end
- end
- for name, item in items do
- if type(item) == "table" then
- forEachTable(item)
- end
- end
- return items[1]
- end
- local input = {
- yes = true,
- no = false,
- nested = {
- yes = 1,
- no = 0,
- },
- metatable = setmetatable({}, {
- yes = 424,
- })
- }
- input.cyclic = input
- local str = convertTableToString(input)
- print(str)
- local tbl = convertStringToTable(str)
- print(tbl)
- print(getmetatable(tbl.metatable))
- print(convertTableToString(tbl))
- -- "m" sets the metatable
- print(convertStringToTable([[
- {
- ["gyat lil bro"] -5.30;
- [531] true;
- [53] "yuh";
- [i 1] i 1;
- [i 2] i 3;
- [i 3] {} m {};
- }
- true
- false
- ]]))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement