User:Iconmaster/rpos.lua

From Esolang
Jump to navigation Jump to search

Implements RPOS in Lua. In order for this to work, there needs to be a folder named 'RposData' in the same place as rpos.lua!

-------------------------------------------------------
--
--	RPOS v2.2
--	Made By Joshua Robbins
--	The Reverse Polish Operating System
--	Made on 2/17/11, Last modified on 3/20/11
--
-------------------------------------------------------


stack = {}
cmdn = ""
sys = {}
vars = {sys = sys}
root = vars
path = {}
pname = {}
cpn = "root"
funcs = {}
pref = {}
help = {}
libfrom = {}
libs = {}

--sys vars declaration

sys["errs"] = 1
sys["disp"] = 0
sys["srcchr"] = "_"
sys["repchr"] = " "
sys["version"] = 2.2
sys["bdate"] = "3/20/11"
sys["joinchr"] = ""
sys["inc"] = 1
sys["pcf1"] = ""
sys["pcf2"] = "S"
sys["pcf3"] = " > "
sys["errmsg"] = ""
sys["pshloop"] = 1
sys["term"] = 0
sys["libs"] = libs
sys["platform"] = "lua"


-- Function declaration

funcs["add"] = function()
	local args = {}
	if GetArgs(args,2,"number","number") then return end
	push(args[1]+args[2])
end

funcs["sub"] = function()
	local args = {}
	if GetArgs(args,2,"number","number") then return end
	push(args[1]-args[2])
end

funcs["mul"] = function()
	local args = {}
	if GetArgs(args,2,"number","number") then return end
	push(args[1]*args[2])
end

funcs["div"] = function()
	local args = {}
	if GetArgs(args,2,"number","number") then return end
	push(args[1]/args[2])
end

funcs["disp"] = function()
	if CheckStack(1) then return end
	print(pop())
end

funcs["peek"] = function()
	if CheckStack(1) then return end
	print(peek())
end

funcs["dup"] = function()
	if CheckStack(1) then return end
	push(peek())
end

funcs["drop"] = function()
	if CheckStack(1) then return end
	pop()
end

funcs["swap"] = function()
	local args = {}
	if GetArgs(args,2) then return end
	push(args[1])
	push(args[2])
end

funcs["rot"] = function()
	local args = {}
	if GetArgs(args,3) then return end
	push(args[1])
	push(args[2])
	push(args[3])
end

funcs["clear"] = function()
	stack = {}
end

funcs["cls"] = function()
	os.execute("cls")
end

funcs["dump"] = function()
	for i,v in ipairs(stack) do
		print(i .. " : " .. dform(v))
	end
end

funcs["mkdir"] = function()
	local args = {}
	if GetArgs(args,1,"string") then return end
	vars[args[1]] = {}
end

funcs["chdir"] = function()
	local args = {}
	local v,dir
	if GetArgs(args,1,"string") then return end
	v = CheckIsDir(args[1],false,true)
	if not v then return end
	table.insert(path,vars)
	table.insert(pname,cpn)
	vars = v
	cpn = args[1]
	if args[1] == ".." then
		dir = table.remove(path)
		cpn = table.remove(pname)
		vars = dir
	else
		table.insert(path,vars)
		table.insert(pname,cpn)
		vars = v
		cpn = args[1]
	end
end

funcs["del"] = function()
	local args = {}
	if GetArgs(args,1,"string") then return end
	if not vars[args[1]] then err("Undefined item "..v) return end
	vars[args[1]] = nil
end

funcs["rcl"] = function()
	local args = {}
	if GetArgs(args,1,"string") then return end
	local v = CheckIsVar(args[1])
	if not v then return end
	push(v)
end

funcs["sto"] = function()
	local args = {}
	if GetArgs(args,2,"string") then return end
	vars[args[1]] = args[2]
end

funcs["list"] = function()
	local i,v
	for i,v in pairs(vars) do
		print(i .. " : " .. dform(v))
	end
end

funcs["dir"] = function()
	if vars == root then print("root") return end
	print(table.concat(pname,"\\").."\\"..cpn)
end

funcs["exec"] = function()
	local args = {}
	if GetArgs(args,1,"string") then return end
	parse(args[1])
end

funcs["eq"] = function()
	local args = {}
	if GetArgs(args,2) then return end
	if args[1]==args[2] then push(1) else push(0) end
end

funcs["ne"] = function()
	local args = {}
	if GetArgs(args,2) then return end
	if args[1]~=args[2] then push(1) else push(0) end
end

funcs["lt"] = function()
	local args = {}
	if GetArgs(args,2) then return end
	if args[1]<args[2] then push(1) else push(0) end
end

funcs["le"] = function()
	local args = {}
	if GetArgs(args,2) then return end
	if args[1]<=args[2] then push(1) else push(0) end
end

funcs["gt"] = function()
	local args = {}
	if GetArgs(args,2) then return end
	if args[1]>args[2] then push(1) else push(0) end
end

funcs["ge"] = function()
	local args = {}
	if GetArgs(args,2) then return end
	if args[1]>=args[2] then push(1) else push(0) end
end

funcs["not"] = function()
	local args = {}
	if GetArgs(args,1,"number") then return end
	if args[1]==1 then push(0) else push(1) end
end

funcs["and"] = function()
	local args = {}
	if GetArgs(args,2,"number","number") then return end
	if args[1]==1 and args[2]==1 then push(1) else push(0) end
end

funcs["or"] = function()
	local args = {}
	if GetArgs(args,2,"number","number") then return end
	if args[1]==1 or args[2]==1 then push(1) else push(0) end
end

funcs["doif"] = function()
	local args = {}
	if GetArgs(args,2,"string","number") then return end
	if args[2]==1 then parse(args[1]) end
end

funcs["while"] = function()
	local args = {}
	if GetArgs(args,2,"string","string") then return end
	parse(args[2])
	if pop()==0 then return end
	while true do
		parse(args[1].." "..args[2])
		if pop()==0 then return end
	end
end

funcs["rep"] = function()
	local args = {}
	local i
	if GetArgs(args,2,"string","number") then return end
	for i=1,args[2] do
		if sys["pshloop"]==1 then push(i) end
		parse(args[1])
	end
end

funcs["repdir"] = function()
	local args = {}
	local i,v,d
	if GetArgs(args,2,"string","string") then return end
	d = CheckIsDir(args[2],true,true)
	if not d then return end
	for i,v in pairs(d) do
		if sys["pshloop"]==1 then push(i) end
		parse(args[1])
	end
end

funcs["size"] = function()
	local args = {}
	local i,v,d,c
	if GetArgs(args,1,"string") then return end
	d = CheckIsDir(args[2],true,true)
	if not d then return end
	c = 0
	for i,v in pairs(d) do
		c = c + 1
	end
	push(c)
end

funcs["join"] = function()
	local args = {}
	if GetArgs(args,2) then return end
	push(args[1]..sys["joinchr"]..args[2])
end

funcs["move"] = function()
	local args = {}
	local od,nd
	if GetArgs(args,2,"string","string") then return end
	od = CheckIsDir(args[2])
	if not od then return end
	nd = CheckIsDir(args[1],false,true)
	if not nd then return end
	nd[args[2]] = od
	vars[args[2]] = nil
	if args[1]==".." then parse(">..") end
end

funcs["ren"] = function()
	local args = {}
	local od,nd
	if GetArgs(args,2,"string","string") then return end
	od = vars[args[2]]
	if not od then err("Undefined item "..args[2]) return end
	nd = args[1]
	vars[nd] = od
	vars[args[2]] = nil
end

funcs["copy"] = function()
	local args = {}
	local od,nd
	if GetArgs(args,2,"string","string") then return end
	od = CheckIsDir(args[2])
	if not od then return end
	nd = CheckIsDir(args[1],false,true)
	if not nd then return end
	nd[args[2]] = copy(od)
end

funcs["write"] = function()
	local v,tot
	tot = ""
	while true do
		v = io.read(1)
		if string.byte(v)==4 then break end
		tot = tot .. v
	end
	push(string.sub(tot,1,-2))
end

funcs["func"] = function()
	local args = {}
	if GetArgs(args,2,"string","string") then return end
	funcs[args[1]] = loadstring("parse(\""..args[2].."\")")
	libs.custom[args[1]] = args[2]
	libfrom[args[1]] = "custom"
end

funcs["isvar"] = function()
	local args = {}
	if GetArgs(args,1,"string") then return end
	args = vars[args[1]]
	if args then push(1) else push(0) end
end

funcs["isdir"] = function()
	local args = {}
	if GetArgs(args,1,"string") then return end
	args = vars[args[1]]
	if type(args)=="table" then push(1) else push(0) end
end

funcs["isfunc"] = function()
	local args = {}
	if GetArgs(args,1,"string") then return end
	if funcs[args[1]] then push(1) else push(0) end
end

funcs["delfunc"] = function()
	local args = {}
	if GetArgs(args,1,"string") then return end
	funcs[args[1]] = nil
	libs[libfrom[args[1]]][args[1]] = nil
	libfrom[args[1]] = nil
end

funcs["alias"] = function()
	local args = {}
	if GetArgs(args,2,"string","string") then return end
	funcs[args[1]] = funcs[args[2]]
	libs.custom[args[1]] = args[2]
	libfrom[args[1]] = "custom"
end

funcs["type"] = function()
	local args = {}
	if GetArgs(args,1) then return end
	push(type(args[1]))
end

funcs["tos"] = function()
	if CheckStack(1) then return end
	push(tostring(pop()))
end

funcs["ton"] = function()
	if CheckStack(1) then return end
	push(tonumber(pop()))
end

funcs["prompt"] = function()
	local v
	if CheckStack(1) then return end
	v = pop()
	if v=="S" then
		pr2 = function() return #stack end
	elseif v=="D" then
		pr2 = function() if vars==root then return "root" else return table.concat(pname,"\\").."\\"..cpn end end
	elseif v=="C" then
		pr2 = function() return cpn end
	elseif v=="T" then
		pr2 = function() return (peek() or "nil") end
	else
		pr2 = function() return "" end
	end
end

funcs["lib"] = function()
	local args = {}
	local f,cont,i,v,s
	if GetArgs(args,1,"string") then return end
	args = args[1]
	f = io.open("RposData\\"..args..".rlib","r")
	cont = f:read("*a")
	lib = {}
	if not libs[args] then libs[args] = {} end
	s = loadstring(cont)
	if s then s() else err("Syntax error in library "..args) return end
	for i,v in pairs(lib) do
		funcs[i] = v
		libs[args][i] = i
		libfrom[i] = args
	end
	addhelp(args[1])
end

funcs["libcmd"] = function()
	local args = {}
	local f,cont,i,v,s
	if GetArgs(args,2,"string","string") then return end
	f = io.open("RposData\\"..args[1]..".rlib","r")
	cont = f:read("*a")
	lib = {}
	if not libs[args[1]] then libs[args[1]] = {} end
	s = loadstring(cont)
	if s then s() else err("Syntax error in library "..args[1]) return end
	for i in string.gmatch(args[2],"%S+") do
		funcs[i] = lib[i]
		libs[args[1]][i] = i
		libfrom[i] = args[1]
	end
	addhelp(args[1])
end

funcs["substr"]=function()
	if CheckStack(3) or CheckTypes("number","number","string") then return end
	local s3 = pop()
	local s2 = pop()
	local s1 = pop()
	push(string.sub(s1,s2,s3))
end

funcs["len"] = function()
	if CheckStack(1) or CheckTypes("string") then return end
	push(#pop())
end

funcs["import"] = function()
	local args = {}
	local f,cont,i,v,s
	if GetArgs(args,1,"string") then return end
	f = io.open("RposData\\"..args[1]..".rfil","r")
	cont = f:read("*a")
	push(cont)
end

funcs["export"] = function()
	local args = {}
	local f,cont,i,v,s
	if GetArgs(args,2,"string") then return end
	f = io.open("RposData\\"..args[1]..".rfil","w")
	f:write(args[2])
end

funcs["inp"] = function()
	push(io.read("*l"))
end

funcs["call"] = function()
	local args = {}
	local f,cont,i,v,s
	if GetArgs(args,1,"string") then return end
	f = io.open("RposData\\"..args[1]..".rfil","r")
	cont = f:read("*a")
	parse(cont)
end

funcs["run"] = function()
	local args = {}
	local f,cont,i,v,s
	if GetArgs(args,1,"string") then return end
	f = io.open("RposData\\"..args[1]..".rfil","r")
	cont = f:read("*a")
	s = loadstring(cont)
	if s then s() else err("Syntax error in file "..args[1]) return end
end

funcs["save"] = function()
	local f
	sav = "return "..save(root)
	f = io.open("RposData\\saved.rsav","w")
	f:write(sav)
end

funcs["load"] = function()
	sav = loadfile("RposData\\saved.rsav")
	if sav == nil then err("Corrupted or nonexistant save file") return end
	root = sav()
	sys = root.sys
	vars = root
	path = {}
	pname = {}
	cpn = "root"
	sys.libs = libs
end

funcs["exit"] = function()
	if io.open("RposData\\onexit.rfil","r") then parse(io.open("RposData\\onexit.rfil","r"):read("*a")) end
	os.exit()
end

funcs["info"] = function()
	print("RPOS v"..sys["version"])
	print("Made by Joshua Robbins")
	print("Current Build: "..sys["bdate"])
	print("")
end

funcs["pshdir"] = function()
	if vars == root then push("") return end
	push(table.concat(pname,"\\",2).."\\"..cpn)
end

funcs["popdir"] = function()
	local s1
	if CheckStack(1) then return end
	s1 = pop()
	vars = root
	for str in string.gmatch(s1,"[^\\]+") do
		parse(">"..str)
	end
end

funcs["root"] = function()
	vars = root
	path = {}
	pname = {}
	cpn = "root"
end

funcs["help"] = function()
	local inp
	print([[
Welcome to RPOS Interactive Help!
Tpye the name of a command or a help topic to see it's help file, or type 'exit' to quit.
]])
	while true do
		io.write(">> ")
		inp = io.read("*l")
		if inp == "exit" then break end
		if help[inp] then print(help[inp]) else print("There is no help file for "..inp..".") end
	end
end

-- Prefix declaration

pref["\'"] = function(arg)
	push(arg)
end

pref["\""] = function(arg)
	push(string.gsub(arg,sys["srcchr"],sys["repchr"]))
end

pref["$"] = function(arg)
	local v = CheckIsVar(arg)
	if not v then return end
	push(v)
end

pref["="] = function(arg)
	local args = {}
	if GetArgs(args,1) then return end
	vars[arg] = args[1]
end

pref[">"] = function(arg)
	local v
	v = CheckIsDir(arg,false,true)
	if not v then return end
	if arg == ".." then
		dir = table.remove(path)
		cpn = table.remove(pname)
		vars = dir
	else
		table.insert(path,vars)
		table.insert(pname,cpn)
		vars = v
		cpn = arg
	end
end

pref[":"] = function(arg)
	vars[arg] = {}
end

pref["~"] = function(arg)
	if not vars[arg] then err("Undefined item "..v) return end
	vars[arg] = nil
end

pref["?"] = function(arg)
	if CheckStack(1) then return end
	if pop()==1 then parse(arg) end
end

pref["@"] = function(arg)
	local i,v,d
	d = CheckIsDir(arg,true,true)
	if not d then return end
	for i,v in pairs(d) do
		print(i .. " : " .. dform(v))
	end
end

pref["#"] = function(arg)
	local c,d,i,v
	d = CheckIsDir(arg,true,true)
	if not d then return end
	c = 0
	for i,v in pairs(d) do
		c = c + 1
	end
	print(c)
end

pref["&"] = function(arg)
	print(dform(vars[arg]))
end

pref["}"] = function(arg)
	local v,tot
	tot = ""
	while true do
		v = io.read(1)
		if string.byte(v)==4 then break end
		tot = tot .. v
	end
	vars[arg] = string.sub(tot,1,-2)
end

pref["*"] = function(args)
	local f,cont,i,v,s
	f = io.open("RposData\\"..args..".rlib","r")
	cont = f:read("*a")
	lib = {}
	if not libs[args] then libs[args] = {} end
	s = loadstring(cont)
	if s then s() else err("Syntax error in library "..args) return end
	for i,v in pairs(lib) do
		funcs[i] = v
		libs[args][i] = i
		libfrom[i] = args
	end
end

pref["%"] = function(arg)
	local f,cont,i,v,s
	f = io.open("RposData\\"..arg..".rfil","r")
	cont = f:read("*a")
	parse(cont)
end

pref["+"] = function(arg)
	if not CheckIsVar(arg) then return end
	vars[arg] = vars[arg] + sys["inc"]
end

pref["-"] = function(arg)
	if not CheckIsVar(arg) then return end
	vars[arg] = vars[arg] - sys["inc"]
end

-- Add all funcs to 'core' lib and add help file

libs["core"] = {}
libs["custom"] = {}
for i,v in pairs(funcs) do
	libs["core"][i] = i
	libfrom[i] = "core"
end

-- Helper functions declaration

function GetArgs(t,n,...)
	if CheckStack(n) then return true end
	local i,v,typs
	typs = {...}
	for i=1,n do
		v = pop()
		if typs[i] == nil or type(v)==typs[i] then
			table.insert(t,v)
		else
			err("Invalid data type of argument #"..i.." of command "..cmdn)
			return true
		end
	end
end

function push(var)
	table.insert(stack,var)
	if sys["disp"]==1 then print(var) end
end

function pop()
	return table.remove(stack)
end

function CheckStack(n)
	if #stack < n then err("Not enough arguments to command "..cmdn) end
	return #stack < n
end

function peek()
	return stack[#stack]
end

function dform(v)
	if type(v) == "table" then return "<DIR>" else return v end
end

function CheckTypes(...)
	local i,v,p
	p = #stack
	for i,v in pairs({...}) do
		if type(stack[p]) ~= v then
			err("Invalid data type of argument #"..i.." of command "..cmdn)
			return true
		end
		p = p-1
	end
	return false
end

function err(msg)
	if sys["errs"] == 0 then return end
	print("ERROR: "..msg)
	sys["errmsg"] = msg
	if sys["term"] == 1 then error("RPOS: term enabled.") end
end

function prompt()
	return sys["pcf1"]..pr2()..sys["pcf3"]
end

function pr2()
	return #stack
end

function CheckIsVar(v)
	if vars[v] == nil then
		err("Undefined variable "..v)
		return false
	end
	if type(vars[v])=="table" then
		err("Invalid variable "..v.." (Var expected, got dir)")
		return false
	end
	return vars[v]
end

function CheckIsDir(v,onedot,twodot)
	if onedot and v=="." then
		return vars
	end
	if twodot and v==".." then
		if vars == root then err("Cannot go up beyond root") return false end
		return path[#path]
	end
	if vars[v] == nil then
		err("Undefined directory "..v)
		return false
	end
	if type(vars[v]) ~= "table" then
		err("Invalid directory "..v.." (Dir expected, got var)")
	end
	return vars[v]
end

function copy(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for index, value in pairs(object) do
            new_table[_copy(index)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end

function save(dd)
	local i,v,ret
	ret = "{"
	for i,v in pairs(dd) do
		ret = ret .. "[\"" .. i .."\"]="
		if type(v) == "table" then
			ret = ret .. save(v)
		elseif type(v) == "string" then
			ret = ret .. "\"" .. v .. "\""
		elseif type(v) == "number" then
			ret = ret .. v
		else
			ret = ret .. "nil"
		end
		ret = ret .. ","
	end
	ret = ret .. "}"
	return ret
end

function addhelp(filename)
	local f,c,n,v
	f = io.open("RposData\\"..filename..".rhlp")
	if not f then return end
	c = f:read("*a")
	for n,v in string.gmatch(c,"<([^<>]*)>([^<>]*)<") do
		help[n]=v
	end
end

--Main logic

function parse(inp)
	local v,i,cmds
	cmds = {}
	for v in string.gmatch(inp,"%S+") do
		table.insert(cmds,v)
	end
	for i,v in ipairs(cmds) do
		cmdn = v
		if funcs[v] then
			funcs[v]()
		elseif pref[string.sub(v,1,1)] then
			pref[string.sub(v,1,1)](string.sub(v,2))
		elseif tonumber(v) then
			push(tonumber(v))
		else
			err("Invalid command "..v)
		end
	end
end

funcs.info()
if io.open("RposData\\onstart.rfil","r") then parse(io.open("RposData\\onstart.rfil","r"):read("*a")) end
addhelp("core")

while true do
	io.write(prompt())
	inp = io.read("*l")
	pcall(parse,inp)
end