require("dms.utils") local Stack = require("dms.stack") local Chunk = require("dms.chunk") local Cmd = require("dms.cmd") local ENTR,ENAB,DISA,LOAD,VERN,USIN,STAT,DISP,ASGN,LABL,CHOI,OPTN,FORE,UNWN,WHLE,FNWR,FNNR,IFFF,ELIF,ELSE,DEFN = "ENTR","ENAB","DISA","LOAD","VERN","USIN","STAT","DISP","ASGN","LABL","CHOI","OPTN","FORE","????","WHLE","FNWR","FNNR","IFFF","ELIF","ELSE","DEFN" local controls = {STAT,CHOI,FORE,WHLE,IFFF,ELIF,ELSE} local flags = {ENTR,ENAB,DISA,LOAD,VERN,USIN,DEFN} local recognizedFlags = { "debugging", "noprint", "warnings" } local parser = {} parser.__index = parser function parser:new(path) local c = {} setmetatable(c,self) c.filename = path or error("Must provied a path!") c.content = io.open(c.filename,"rb"):read("*a") c.flags = {} c.chunks = {} c.ver = {1,0,0} c.pos = 0 c.lines = {} return c end function parser:setVersion(ver) self.ver = ver end -- Output Stuffs function parser:debug(...) if not self.flags.debugging then return end self:print(...) end function parser:print(...) if self.flags.noprint then return end print(...) end function parser:error(err,line) if not line then print(err) os.exit() end print("Error: <"..line[4]..":"..line[1].."> \""..line[5].."\" "..err) os.exit() end function parser:warn(msg,line) if not self.flags.warnings then return end if not line then print(msg) return end print("Warning: <"..line[4]..":"..line[1].."> \""..line[5].."\" "..msg) end function parser:manageFlag(line) if self:isFlag(line) then local flag = line[3] local dat = line[5]:match("%s+(.+)$") if flag == ENTR then if self.entry then self:error("Entry was already set to: "..self.entry,line) else self.entry = dat end elseif flag == ENAB then if not self:isRecognizedFlag(dat) then self:warn("Flag \""..dat.."\" is not recognized!",line) end self.flags[dat] = true elseif flag == DISA then if not self:isRecognizedFlag(dat) then self:warn("Flag \""..dat.."\" is not recognized!",line) end self.flags[dat] = false elseif flag == LOAD then -- TODO elseif flag == VERN then local v local a,b,c = dat:match("(%d*)%.?(%d*)%.?(%d*)") a,b,c = tonumber(a),tonumber(b) or 0,tonumber(c) or 0 if a>self.ver[1] or a>self.ver[2] then self:warn("This script was created for a different version of the DMS! Code may behave unexpectedly or not work at all!",line) end elseif flag == USIN then -- TODO end else self:error("Flag Expected! Got: "..line[3],line) end end function parser:isControl(line) for i,v in pairs(controls) do if line[3] == v then return true end end return false end function parser:isFlag(line) for i,v in pairs(flags) do if line[3] == v then return true end end return false end function parser:isRecognizedFlag(flag) for i,v in pairs(recognizedFlags) do if v == flag:lower() then return true end end return false end function parser:parse() local link = self local line_num = 0 local choice local group = 0 local lastgroup = 0 local groupStack = Stack:new({}) local lastpop local noblock = true local arr = {} local multilined = false function groupStack:append(t) local c = self:peek() val = pcall(function() table.insert(c,1,t) end) if not val then link:error("Inconsistant indentation!",t) end end groupStack:push({}) for line in self.content:gmatch("(.-)\n") do line_num = line_num + 1 line = line:gsub("//(.+)$","") -- Filter out comments if not multilined and line:match("/%*(.+)$") then multilined = true line = line:gsub("/%*(.*)$","") end if multilined then if line:match("%*/") then multilined = false line = line:gsub("(.+)%*/","") if #line:trim() == 0 then goto continue end else goto continue end end if line:trim()=="" then goto continue end -- Skip all whitespace completely lastgroup = group group = line:tabs() if lastgroup>group then for i=1,lastgroup-group do local c = groupStack:pop() lastpop = c for i,v in pairs(c) do table.insert(arr,v) end end elseif lastgroup ".. table.concat(vars,", ") end self.current_chunk:addCmd(cmd) end function parser:parseASGN(line) local vars,assigns = line[5]:match("(.-)%s*=%s*(.+)") vars = vars:split() assigns = assigns:split() local cmd = Cmd:new(line,ASGN,{vars = vars, assigns = assigns}) function cmd:tostring() return "DATA -> "..table.concat(vars,", ") end self.current_chunk:addCmd(cmd) -- TODO: make dict lookups builtin end function parser:parseChoice(line) local text = line[5]:match("\"(.+)\"") local copt = self:peek() local choice = {text = text} local cmd = Cmd:new(line,CHOI,choice) if copt[3]~=OPTN then self:error("Choices must have at least one option to choose!") return end while copt do copt = self:next() local a,b = copt[5]:match("(.+) %s*(.+)") print(a,"|",b) copt = self:peek() if copt[3]~=OPTN then break end end -- We need to get functions working first end function parser:parseDialogue(line) local targ,text = line[5]:match("(%w*)%s*(.*)") if #targ == 0 then targ = nil end local cmd = Cmd:new(line,DISP,{text=text,target=targ}) function cmd:tostring() return table.concat({targ or "@",text},", ") end self.current_chunk:addCmd(cmd) end function parser:peek() return self.lines[self.pos + 1] end function parser:next() self.pos = self.pos + 1 return self.lines[self.pos] end return parser