HashedPoem

Something interesting is that this esolang is the 24th esolang invented in the year 2024 (on this wiki).
==Programs==
HashedPoem programs consists of words separated by whitespaces (spaces, tabs, linefeeds). Each word has a hash value, the hash of a lowercase string a0a1a2...al-1 can be computed using this expression:
:h=\left(\sum_{i=0}^{l-1}256^ia_i\right)\bmod7
If one can't see math tags, there is the expression in image form:
To be more clear, a Python function computing the hash value is as follows:
 computehash=lambda x:sum((ord(j)*pow(256,i,7))%7 for i,j in enumerate(x))%7
When computing the hash value of a non-lowercase string, it converts to lowercase first.
For convenience, the following table lists some words with every hash value:
Hash	Words
0 	or, fuck, with, can, to
1 	no, its, of, at
2 	oh, it, let, hello, word
3 	this, down, thanks
4 	then, as, for, get
5 	is, on, brain, brainfuck
6 	yes, esolang, there, the, a
If two words have the same hash value, they are treated equally in HashedPoem.
For convenience, let's call the words with hash value i i-hashed words.
A program doesn't have to make sense (you can even include words that are not in English), but it has to be valid, that means you can even write:
 is is is is is is is or
but not:
 is is is is is is is
but writing a valid HashedPoem program that makes sense can be a challenge, because it's hard.
Non-letters are ignored, that means:
 *#?_
has a hash of 0.
==Memory==
It uses an unbounded tape. Every cell has a unique nonnegative address, address 0 is the first cell, address 1 is the second, address 2 is the third, etc. The cells contain unbounded signed intergers. Initiall, address 0 contains 1, all the other addresses are 0.
==Integer representation==
Since HashedPoem programs consist entirely of words and words have only 7 possible hash values, HashedPoem cannot use decimal to represent integers, instead, it uses base-6. A number is represented by a sequence of words ending with a 0-hashed word, all the words except the last one are nonzero-hashed. A digit is represented by a nonzero-hashed word, its value is the word's hash minus 1.
For example, the sequence of words:
 this is because
when hashed, becomes:
 3 5 0
which becomes 24 in base-6, which is 16 in decimal.
When there is no digit in an integer, it represents 0, so:
 because
represents 0.
There is no way to represent negative integers directly in code, but you can use arithmetic operations to calculate one.
==Commands==
Commands are assembly-like.
Hash	Command 	Meaning
0 	ADD <integer1> <integer2>	Add the cells with addresses <integer1> and <integer2> and store the result in <integer1>
1 	SUB <integer1> <integer2>	Subtract the cells with addresses <integer1> and <integer2> and store the result in <integer1>
2 	MUL <integer1> <integer2>	Multiply the cells with addresses <integer1> and <integer2> and store the result in <integer1>
3 	IO <word> <integer> 	If the hash of the word is even, print the cell with address <integer> as Unicode, otherwise input the cell with address <integer2> as Unicode
4 	REF <integer> 	Set the cell with address <integer> to the cell addressed the absolute value of the value of the cell with address <integer>.
5 	LABEL <integer> 	Defines a label with an ID of <integer>, if a label with this ID already exists, the program errors.
6 	JMP <integer1> <integer2>	If the cell with address <integer1> is nonzero, jump to the label with the ID <integer2>, if there isn't a label with the ID <integer2>, the program errors.
==Code==
===Assemblers===
Currently, there exists a low-level assembler that assembles to hashed HashedPoem in Python. (Note, this assembler automatically converts decimal to base-6, so write in decimal)
import sys
code=map(lambda x:x.split(),sys.stdin.read().split('\n'))
res=''
def dec2base6(x):
 r='0'
 while x:
 r=str(x%6+1)+r
 x//=6
 return r
for i in code:
 try:
 c=i[0].upper()
 if c=='ADD':
 res+='0'+dec2base6(int(i[1]))+dec2base6(int(i[2]))
 if c=='SUB':
 res+='1'+dec2base6(int(i[1]))+dec2base6(int(i[2]))
 if c=='MUL':
 res+='2'+dec2base6(int(i[1]))+dec2base6(int(i[2]))
 if c=='IO':
 res+='3'+i[1]+dec2base6(int(i[2]))
 if c=='REF':
 res+='4'+dec2base6(int(i[1]))
 if c=='LABEL':
 res+='5'+dec2base6(int(i[1]))
 if c=='JMP':
 res+='6'+dec2base6(int(i[1]))+dec2base6(int(i[2]))
 except:
 pass
print(res)
Example:
LABEL 0
JMP 0 0
Assembles to:
 50600
===Interpreters===
In Python:
import sys
class Tape:
 def __init__(self):
 self.data={0:1}
 def __getitem__(self,item):
 if item in self.data:
 return self.data[item]
 else:
 return 0
 def __setitem__(self,item,x):
 self.data[item]=x
_computehash=lambda x:sum((ord(j)*pow(256,i,7))%7 for i,j in enumerate(x))%7
computehash=lambda x:_computehash(.join(filter(lambda y:y.isalpha(),x.lower())))
hashall=lambda x:.join(map(str,map(computehash,x.split())))
def nextword(x): # separate the first word
 return (int(x[0]),x[1:])
def _nextnum(x):
 p=x.find('0')
 if p==-1:
 raise SyntaxError('Missing ending zero-hashed word in number')
 return (x[:p],x[p+1:])
def nextnum(x): # separate the next integer
 ns,nx=_nextnum(x)
 r=0
 for i in ns:
 r=r*6+int(i)-1
 return (r,nx)
def disasm(x): # Disassemble code to a list of tuples of integers
 ha=hashall(x)
 res=[]
 ha=.join(filter(lambda x:x in '0123456',ha))
 while ha:
 i,ha=nextword(ha)
 i=str(i)
 if i in '0126':
 a,ha=nextnum(ha)
 b,ha=nextnum(ha)
 res.append((int(i),a,b))
 elif i in '45':
 a,ha=nextnum(ha)
 res.append((int(i),a))
 else:
 a,ha=nextword(ha)
 b,ha=nextnum(ha)
 res.append((int(i),a,b))
 return res
def getchar():
 c=sys.stdin.read(1)
 return (ord(c) if c else 0)%256
def interpret_asm(x): # Interpret the disassembled code
 ip=0
 tape=Tape()
 labels={}
 for j,i in enumerate(x):
 if i[0]==5: # LABEL
 if i[1] in labels:
 raise SyntaxError("Duplicate label ID")
 labels[i[1]]=j
 while ip<len(x):
 c=x[ip]
 opcode=c[0]
 if opcode==0: # ADD
 tape[c[1]]+=tape[c[2]]
 if opcode==1: # SUB
 tape[c[1]]-=tape[c[2]]
 if opcode==2: # MUL
 tape[c[1]]*=tape[c[2]]
 if opcode==6: # JMP
 if tape[c[1]]:
 if c[2] not in labels:
 raise SyntaxError("Label ID does not exist")
 ip=labels[c[2]]
 continue
 if opcode==4: # REF
 tape[c[1]]=tape[abs(tape[c[1]])]
 if opcode==3: # IO
 if not (c[1]&1): # even: print
 print(chr(tape[c[2]]),end=)
 else: # odd: input
 tape[c[2]]=getchar()
 ip+=1
def interpret(x):
 return interpret_asm(disasm(x))
if __name__=='__main__':
 interpret(sys.stdin.read())
===Unhashers===
This is a random unhasher in Python, it unhashes to meaningless code, because, as the previous text claimed, writing a program that makes sense is hard:
from random import choice
_computehash=lambda x:sum((ord(j)*pow(256,i,7))%7 for i,j in enumerate(x))%7
computehash=lambda x:_computehash(.join(filter(lambda y:y.isalpha(),x.lower())))
def rndgen():
 return .join(choice('QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm') for i in range(10))
def gen(x):
 r=rndgen()
 while computehash(r)!=x:
 r=rndgen()
 return r
c=input()
d=[gen(int(i)) for i in filter(lambda x:x in '0123456',c.strip())]
for i in range(len(d)//5):
 print(d[i*5],d[i*5+1],d[i*5+2],d[i*5+3],d[i*5+4])
for i in range(len(d)%5):
 print(d[len(d)//5*5+i],end=' ')
An improvement on the above, generates meaningless "words".
from random import choice
_computehash=lambda x:sum((ord(j)*pow(256,i,7))%7 for i,j in enumerate(x))%7
computehash=lambda x:_computehash(.join(filter(lambda y:y.isalpha(),x.lower())))
def rndgen():
 return choice('im in il un dis ad re de inter mis '.split(' '))+choice('act add substract switch hash unhash jump label multiply program research create implement interpret prove and or xor not'.split())+choice('ed tion ation ion er or ist '.split(' '))
def gen(x):
 r=rndgen()
 while computehash(r)!=x:
 r=rndgen()
 return r
c=input()
d=[gen(int(i)) for i in filter(lambda x:x in '0123456',c.strip())]
for i in range(len(d)//5):
 print(d[i*5],d[i*5+1],d[i*5+2],d[i*5+3],d[i*5+4])
print(*d[len(d)//5*5:])
==Examples==
===Infinite loop===
 is to yes can can
but actually, it can make more sense:
 Brainfuck or esolang? Fuck !
The space between Fuck and ! is mandatory.
Hashed:
 50600
Disassembled:
LABEL 0
JMP 0 0
===Truth Machine===
Currently, the code is only available in hashed form:
 00000000000002000200020031003001020503030600
and meaningless form:
interlabelion ilnotist disimplementist rehashor or
ilxortion resubstraction programtion labelor substraction
label or deortion improgram imresearch
reortion or discreate oror injumpion
misinterpretation deadder adsubstractation ilproveation misprogramor
dejumpist imnoted ortion jumper adsubstractist
ilmultiplyist dishash dehash dissubstract iladded
renoted adoror disandor unxored disnottion
uncreateed adprogramist ilandist delabel
And a form that makes a bit of sense, but not much (Written by User:None1):
I love cows .
I love oxen .
I love bad bees ,
That can make food.
However, bees beat cows,
Sting their back.
Whip you .
Hit your back .
You make me eat feet.
Fuck them!
Fuck them!
Make the people fuck!
It takes a lot of time to write that.
Disassembled:
ADD 0 0
ADD 0 0
ADD 0 0
ADD 0 0
ADD 1 0
ADD 1 0
ADD 1 0
IO 1 0
ADD 2 0
SUB 0 1
LABEL 0
IO 1 2
JMP 0 0
If you unhashed it into more meaningful code (code that makes sense), please put it here.
==Computational class==
Turing complete, because the two register minsky machine can be compiled to it (l is the position of the command in the minsky machine program, first command is 1, second command is 2, third is 3, etc. n is the sum of the number of commands in the minsky machine program and l):
 Increment A:
 LABEL l
 ADD 1 0
 
 Increment B:
 LABEL l
 ADD 2 0
 
 If A=0, jump to the i-th minsky machine command, otherwise decrement A:
 LABEL l
 JMP 1 n
 JMP 0 i
 LABEL n
 SUB 1 0
 
 If B=0, jump to the i-th minsky machine command, otherwise decrement B:
 LABEL l
 JMP 2 n
 JMP 0 i
 LABEL n
 SUB 2 0
==See also==
* HashedPoem/Hash dictionary
Category:Languages
Category:2024
Category:Cell-based
Category:Implemented
Category:Pseudonatural
Category:Turing complete