Ero

From Esolang
Jump to navigation Jump to search
This article is not detailed enough and needs to be expanded. Please help us by adding some more information.
This is still a work in progress. It may be changed in the future.
|::
Designed by User:InLuaIKnow
Appeared in 2026
Computational class Unknown
Major implementations Lua

is a esolang written in Lua.

:|: statement terminator
:.(opcode)  makes a statement
|:: signals that arguments are after this
>> argument seperator.

Example(s):

:.1|::1>>"Hello,world!":|:
:.8|::1>>1:|:
:.1|::1>>1:|::.1|::2>>1:|::.2|::1>>2>>3:|::.8|::1>>3:|:

Current intrepeter

--|:: intrepeter
local reg={}
local pc = 1
local functions = {[1]=print,[2]=error,[3]=io.read}
local opc = {
   [1]=function(a,b)--sets a reg
       reg[a]=b
   end;
   [2]=function(a,b,c)--add
       reg[c]=(reg[a]+reg[b])
   end;
   [3]=function(a,b,c)--sub
       reg[c]=(reg[a]-reg[b])
   end;
   [4]=function(a,b,c)--mul
       reg[c]=(reg[a]*reg[b])
   end;
   [5]=function(a,b,c)--div
       reg[c]=(reg[a]/reg[b])
   end;
   [6]=function(a,b,c)--pow
       reg[c]=(reg[a]^reg[b])
   end;
   [7]=function(a,b,c)--mod
       reg[c]=(reg[a]%reg[b])
   end;
   [8]=function(r,a,...)--call
       local args = {}
       for i,v in ipairs({...}) do
          args[i]=reg[v]
       end
       reg[r]=functions[a](table.unpack(args))
   end;
   [9]=function(n)--jump
       
       pc=pc+n-1
   end;
   [10]=function(r,n)--jump if true
       if reg[r] == true then
           pc=pc+n-1
       end
   end;
   [11]=function(o,a,b,r)--compare
       if o==">" then 
           reg[r]=reg[a]>reg[b] 
       elseif o=="<" then
           reg[r]=reg[a]<reg[b]
       elseif o=="==" then
           reg[r]=reg[a]==reg[b]
       elseif o=="!=" then
           reg[r]=reg[a]~=reg[b]
       else
           error("invalid op")
       end
   end;
   [12]=function(a,r)--not
       reg[r]=(not reg[a])
   end;
   [13]=function(a,b,r)--or
       reg[r]=reg[a] or reg[b]
   end;
   [14]=function(a,b,r)--and
       reg[r]=reg[a] and reg[b]
   end;
}


function compile(source)
   local inst = {}
   for stmt in source:gmatch("(.-):|:") do
       local opco = stmt:match("^%:.([0-9]+)|::")
       if opco then
           opco = tonumber(opco)
          -- print(opco)
           local argst = stmt:match("|::(.*)")
           local args = {}
          -- print(argst)
           if argst then
               local argcount = 0
               for argf in argst:gmatch("([^>>]+)") do
                  -- print(argf)
                   argcount=argcount+1
                   local fl = argf:sub(1,1)..argf:sub(-1)
                   local num = tonumber(argf)
                   if num then
                       args[#args+1] = math.floor(num)
                   elseif fl=="" or fl=='""' then
                       args[#args+1] = argf:sub(2,-2)
                   elseif argf=="true" then args[#args+1] = true elseif argf=="false" then args[#args+1] = false 
                   else error("invalid argument #"..argcount) end
               end
           end
           inst[#inst+1]={opcode=opco, args=args}
       end
   end
   return inst
end

function intrepet(p)
   pc = 1
   while pc <= #p do
       local instr = p[pc]
       local op = opc[instr.opcode]
       if op then
           op(table.unpack(instr.args))
       end
       pc = pc + 1
   end
end

if arg[1] == nil then
   print("|:: (Ero), the esoteric language")
   print("!:quit to exit.")
   while true do
       io.write(">")
       local inp=io.read()
       if inp=="!:quit" then return end 
       local ok,res =pcall(compile,inp)
       --print(ok,table.concat(res," "))
       if not ok then io.stderr:write("compilation error: "..res.."\n") else
           local o2, re2 = pcall(intrepet,res)
           if not o2 then io.stderr:write("runtime error: "..re2.."\n") end
       end
   end
elseif arg[2]=="-c" then -- compile to fully binary file
   local infile = arg[1]
   local outfile = arg[3] or (infile .. ".bin")
   local f = io.open(infile, "r")
   if not f then
       io.stderr:write("Cannot open input file: "..infile.."\n")
       return
   end
   local src = f:read("a")
   f:close()
 
   local ok, inst = pcall(compile, src)
   if not ok then
       io.stderr:write("compilation error: "..inst.."\n")
       return
   end

   local f2 = io.open(outfile, "wb")
   if not f2 then
       io.stderr:write("can not open output file: "..outfile.."\n")
       return
   end
   local function write_number(n)
       f2:write(string.pack(">d", n)) -- big-endian double
   end

   local function write_boolean(b)
       f2:write(string.char(b and 1 or 0))
   end

   local function write_string(s)
       local len = #s
       f2:write(string.pack(">H", len)) -- 2 bytes length
       f2:write(s)
   end

   for _, instr in ipairs(inst) do
       f2:write(string.char(instr.opcode or 0))
       local args = instr.args or {}
       f2:write(string.char(#args))
       for _, a in ipairs(args) do
           if type(a) == "number" then
               f2:write(string.char(0))  -- type marker: 0=number
               write_number(math.floor(a))
           elseif type(a) == "boolean" then
               f2:write(string.char(1))  -- type marker: 1=boolean
               write_boolean(a)
           elseif type(a) == "string" then
               f2:write(string.char(2))  -- type marker: 2=string
               write_string(a)
           else
               error("unsupported arg type: "..type(a))
           end
       end
   end

   f2:close()
   print("compiled: "..outfile)


elseif arg[2]=="-oc" then -- open fully binary compiled file
   local infile = arg[1]
   local f = io.open(infile, "rb")
   if not f then
       io.stderr:write("can not open compiled file: "..infile.."\n")
       return
   end

   local data = f:read("a")
   f:close()

   local pos = 1
   local insts = {}

   local function read_number()
       local n
       n, pos = string.unpack(">d", data, pos)
       return n
   end

   local function read_boolean()
       local b = data:byte(pos)
       pos = pos + 1
       return b ~= 0
   end

   local function read_string()
       local len
       len, pos = string.unpack(">H", data, pos)
       local s = data:sub(pos, pos+len-1)
       pos = pos + len
       return s
   end

   while pos <= #data do
       local opcode = data:byte(pos)
       pos = pos + 1
       local argcount = data:byte(pos)
       pos = pos + 1
       local args = {}
       for i=1,argcount do
           local typ = data:byte(pos)
           pos = pos + 1
           if typ == 0 then
               args[i] = read_number()
           elseif typ == 1 then
               args[i] = read_boolean()
           elseif typ == 2 then
               args[i] = read_string()
           else
               error("unknown arg type in")
           end
       end
       insts[#insts+1] = {opcode=opcode, args=args}
   end

   intrepet(insts)
else
   local h=io.open(arg[1],"r")
   local c=h:read("a")h:close()
   local ok,res =pcall(compile,c)
   if not ok then io.stderr:write("compilation error:",res) else intrepet(res) end
end