# parseManager A module for making advance config files. This library depends on my multi library and my bin library Here is an example, this would be its own file called parsetest.txt ```lua ENTRY START ENABLE forseelabels DISABLE leaking ENABLE customcommands -- WIP USING EBIM -- Allows for multilined commands [START]{ --Defualt enviroment is the GLOBAL one, you can create and swap between them whenever you want. You can have as many as you want as well a=100 b=7 c=21 "$a$ $b$ $c$" env=createENV() setENV(env) a=15 b=150 "$a$ $b$ $c$" env=getENV("GLOBAL") setENV(env) "$a$ $b$ $c$" test=a<-env -- get var a from an env and set it to test "Test $test$" test=51 a=test->env -- set var a in env to test "$a$ $b$ $c$" setENV(env) -- lets go back to the modified enviroment "$a$ $b$ $c$" test2=stringLEN("$a$ $b$ $c$") "Test2 $test2$" string test5: -- no need for quotes, everything in the block is considered a string... Also no escaping is needed; however, endstring is not useable as a part of the string... Yo I am able to make a multilined string if i want Now I am at the next line lol! endstring list test6: -- create a multilined list "elem1" 2 3 true false "elem6" env endlist dict test7: name: "Ryan" age: 21 job: "BUM" list: test6 enddict "Test5 $test5$" list=[1,2,3,4] test4=list[2] env["a"]=10 test3=env["a"] "Test3 $test3$" "List $test6[1]$" "List $test6[2]$" "List $test6[3]$" "List $test6[4]$" "List $test6[5]$" "List $test6[6]$" "List $test6[7]$" "Dict $test7[name]$" "Dict $test7[age]$" "Dict $test7[job]$" test9="name" test8=test7[test9] "Test8 $test8$" data=test7[list] data2=data[1] "Test9 $data2$" data=tester2(1,2,3) "Now what are these $a$ $b$ $c$" "$data[name]$" "$data[me]$" ::choices:: "Pick?"< "test1" JUMP(C1) "test2" JUMP(C2) "test3" JUMP(C3) > -- if name=="bob" or name=="ryan": -- "ADMINS" -- elseif name=="Joe" -- "NOT ADMIN" -- else -- "Something else" -- endif } [C1]{ "Hello1" GOTO(choices) } [C2]{ "Hello2" GOTO(choices) } [C3]{ "Hello3" GOTO(choices) } [@:construct]{ -- l is left arg r is the right arg ret=l*(r/100) return(ret) } [tester:function]{ "lets go" nest="hey" } [tester2:function(a,b,c)]{ -- functions return enviroments which can be indexed "Interesting: $a$ $b$ $c$" name="Ryan" age=15 yo=tester() me=yo["nest"] } ``` parsetest2.txt ```lua ENTRY START [START]{ "Hello It is now time to do some tests!" a=15 "a = $a$" b=a@25 test2="Yo $a$ $b$" -- create a string with a and b vars "$test2$" "b = $b$" c=5 "c = $c$" cf=10+(5!)+10 test=(5~5)+5 "c! = $cf$ test = $test$" "All done" JUMP(NOVAR) } [@:construct]{ -- get % out of 100 ret=l/(r/100) return(ret) } [~:construct]{ -- negate variable if r~=NONE then GOTO(sub)|GOTO(neg) ::sub:: ret=l-r return(ret) GOTO(end) ::neg:: ret=0-r return(ret) ::end:: } -- You dont have too many symbols left to use though. For now a symbol is only 1 char long so you are limited [fact:function(n)]{ count=1 stop=n ::loop:: -- for loop kinda, can become a stateloop as well n=n*count count=count+1 if count==stop then GOTO(end)|GOTO(loop) ::end:: ret=n } [neg:function(n)]{ ret=n*(0-1) } --Bind the fact function to the symbol '!' [!:construct]{ env=fact(l) ret=ret<-env return(ret) } [NOVAR]{ ::go:: "I AM HERE!!!" NOVAR="TEST" JUMP(START) } [TEST]{ "We are now here" } ``` Here is the luacode using the library. NOTE: I was doing tests so the test code has blocks of code that should be within the module itself! main.lua ```lua require("bin") require("multi.all") require("parseManager") function parseManager:RunCode(code,entry,sel,env) -- returns an env or selectVarName local file = bin.new("ENTRY "..(entry or "START").."\n"..code) local run=parseManager:load(file) run._methods = self._methods run.defualtENV=self.defualtENV run.defualtENV=self.defualtENV for i,v in pairs(env or {}) do run.defualtENV[i]=v end local t=run:start() while true do if t.Type=="text" then print(t.text) t=run:next() elseif t.Type=="condition" then t=run:next() elseif t.Type=="assignment" then t=run:next() elseif t.Type=="label" then t=run:next() elseif t.Type=="method" then t=run:next() elseif t.Type=="choice" then t=run:next(nil,math.random(1,#t.choices),nil,t) elseif t.Type=="end" then if t.text=="leaking" then -- go directly to the block right under the current block if it exists t=run:next() else return (run.defualtENV[sel] or run.defualtENV) end elseif t.Type=="error" then error(t.text) else t=run:next() end end end parseManager.symbols={} -- {sym,code} function parseManager:registerSymbol(sym,code) self.symbols[#self.symbols+1]={sym,code} end function parseManager:populateSymbolList(o) local str="" for i=1,#self.symbols do str=self.symbols[i][1]..str end return str end function parseManager:isRegisteredSymbol(o,r,v) for i=1,#self.symbols do if self.symbols[i][1]==o then return parseManager:RunCode(self.symbols[i][2],"CODE","ret-urn",{["l"]=r,["r"]=v,["mainenv"]=self.defualtENV}) end end return false --self:pushError("Invalid Symbol "..o.."!") end function parseManager:evaluate(cmd,v) v=v or 0 local loop local count=0 local function helper(o,v,r) if type(v)=="string" then if v:find("%D") then v=self:varExists(v) end end if type(r)=="string" then if r:find("%D") then r=self:varExists(r) end end local r=tonumber(r) or 0 local gg=self:isRegisteredSymbol(o,r,v) if gg then return gg elseif o=="+" then return r+v elseif o=="-" then return r-v elseif o=="/" then return r/v elseif o=="*" then return r*v elseif o=="^" then return r^v end end for i,v in pairs(math) do cmd=cmd:gsub(i.."(%b())",function(a) a=a:sub(2,-2) if a:sub(1,1)=="-" then a="0"..a end return v(self:evaluate(a)) end) end cmd=cmd:gsub("%b()",function(a) return self:evaluate(a:sub(2,-2)) end) for l,o,r in cmd:gmatch("(.*)([%+%^%-%*/"..self:populateSymbolList().."])(.*)") do loop=true count=count+1 if l:find("[%+%^%-%*/]") then v=self:evaluate(l,v) v=helper(o,r,v) else if count==1 then v=helper(o,r,l) end end end if not loop then return self:varExists(cmd) end return v end parseManager.constructType=function(self,name,t,data,filename) if t~="construct" then return end --print(name,t,"[CODE]{"..data.."}") self:registerSymbol(name,"[CODE]{"..data.."}") end parseManager.OnExtendedBlock(parseManager.constructType) test=parseManager:load("parsetest2.txt") -- load the file t=test:start() while true do if t.Type=="text" then print(t.text) t=test:next() elseif t.Type=="condition" then t=test:next() elseif t.Type=="assignment" then t=test:next() elseif t.Type=="label" then t=test:next() elseif t.Type=="method" then t=test:next() elseif t.Type=="choice" then print(t.text) for i=1,#t.choices do print(i..". "..t.choices[i]) end io.write("Choose#: ") cm=tonumber(io.read()) t=test:next(nil,cm,nil,t) elseif t.Type=="end" then if t.text=="leaking" then -- go directly to the block right under the current block if it exists t=test:next() else os.exit() end elseif t.Type=="error" then error(t.text) else t=test:next() end end ``` # Output if using parsetest.txt ``` 100 7 21 15 150 21 100 7 21 Test 15 100 7 21 51 150 21 Test2 9 Test5 Yo I am able to make a multilined string if i want Now I am at the next line lol! Test3 10 List elem1 List 2 List 3 List true List false List elem6 List table: 00B53B98 Dict Ryan Dict 21 Dict BUM Test8 Ryan Test9 data[1] Interesting: 1 2 3 lets go Now what are these 51 150 21 Ryan hey Pick? 1. test1 2. test2 3. test3 Choose#: 2 Hello2 Pick? 1. test1 2. test2 3. test3 Choose#: 3 Hello3 Pick? 1. test1 2. test2 3. test3 Choose#: 1 Hello1 Pick? 1. test1 2. test2 3. test3 Choose#: Pick? 1. test1 2. test2 3. test3 Choose#: ... Would continue forever ``` # Output if running parsetest2.txt ``` Hello It is now time to do some tests! a = 15 Yo 15 60 b = 60 c = 5 c! = 140 test = 5 All done I AM HERE!!! Hello It is now time to do some tests! a = 15 Yo 15 60 b = 60 c = 5 c! = 140 test = 5 All done We are now here ```