MAWP

From Esolang
Jump to navigation Jump to search

MAWP is a stack-based esoteric programming language that was made in 2020.


Language Overview

Version 0.0

MAWP works on an integer stack, starting with an initial value of 1. The base operators are:

Any single-digit integer pushes that integer to stack.
M         takes top two values of the stack and sums them.                               [3,2,1] ==> [3,3]
A         takes top two values of the stack and subtracts the first from the other.      [3,2,1] ==> [3,1]
W         takes top two values of the stack and multiplies them.                         [3,2,1] ==> [3,2]
P         takes top two values of the stack and floor divides the second by the other.   [3,2,1] ==> [3,2]
%         pops top of stack.                                                             [3,2,1] ==> [3,2]
!         duplicates top of stack.                                                       [3,2,1] ==> [3,2,1,1]
:         prints top of stack without newline, removing it.                              [3,2,1] ==> [3,2] (STDOUT:1)
;         prints top of stack as ascii char without newline, popping it.                 [3,2,72]==> [3,2] (STDOUT:H)
.         terminates program
[         start of loop
]         end of loop. If top of stack doesn't equal to 0, then moves back to start of loop. (inspired by brainfuck)
?         conditional. If top of stack doesn't equal to 0, skips next operator.
|         reads a character off STDIN and pushes its ascii value. NOTE:integers still get pushed according to ascii value, not actual integer value.

Version 0.1

MAWP 0.1 introduces several new features, and changes a couple old ones:

 ~         reverses stack                                                                [3,2,1] ==> [1,2,3]
 [         now also jumps to its ] if top of stack equals to 0
 (         start of inverted [] loop. Jumps to its ) if top of stack doesn't equal to 0
 )         end of inverted [] loop. Jumps to its ( if top of stack equals to 0
 <         long conditional. If top of stack doesn't equal to 0, jumps to its >
 >         end of long conditional
 A         now gives the absolute value of the difference
 |         now pushes whole input byte by byte, not only the first one
 _         pushes length of stack                                                        [3,2,1] ==> [3,2,1,3] 

Version 1.0

 {         start of long inverted conditional. If top of stack equals to 0, jumps to its }
 }         end of long inverted conditional
 @         pushes whole input byte by byte. If character is an integer, then push that integer. Else push a 0

Version 1.1

 /         cycles stack clockwise
 \         cycles stack anticlockwise

Version 2.0

 Stack may now hold strings, floating-point and negative numbers.
 Number Literals: Any subsequent numbers from 0 to 9 will now be pushed as one multi-digit number
 M,A,W,P are now 4 global variables. If the previous character before one of the variables was =, then assigns top of stack to the corresponding variable. Else, pushes the variable to stack.
 Strings: Any characters between a pair of " will now get pushed to stack as a string.
 +         Pops two values off of stack. If at least one of the values is a string, pushes a string consisting of two concatenated values. Else, pushes sum of values. ["Hello",3] ==> ["Hello3"]
 -         Pops two values off of stack. If one of the top two values is a string, pushes values and a 0. Else, pushes difference of values. [1,2,3] ==> [1,-1]
 *         Pops two values off of stack. If both of two top values of stack is string, push a 0. Else, if only one of values is a string, pushes the string repeated n times, where n is the other value. Else, push two values multiplied. ["Hello",3] ==> ["HelloHelloHello"]
 $         Pops two values off of stack. If one of the top two values is a string, pushes values and a 0. Else, push result of second value divided by the top. [1,2,3] ==> [1,0.66666666] 
 %         Pops two values off of stack. If one of the top two values is a string, pushes values and a 0. Else, pushes result of second value modulo top value.
 `         Pops top of stack.
 :         Outputs top of stack
 ;         If top of stack is a string, output string as sequence of ASCII codes. Else, output the corresponding ASCII character.

Interpreter

Currently, the only online interpreter available for MAWP is hosted on This page However, here is an reference script written in python 3.8:

 #Ver 0.1
 from time import sleep
 def buildsquarebracemap(code):
   temp_bracestack, bracemap = [], {}
   for position, command in enumerate(code):
       if command == "[": temp_bracestack.append(position)
       if command == "]":
           start = temp_bracestack.pop()
           bracemap[start] = position
           bracemap[position] = start
   return bracemap
 def buildcurlybracemap(code):
   temp_bracestack, bracemap = [], {}
   for position, command in enumerate(code):
       if command == "(": temp_bracestack.append(position)
       if command == ")":
           start = temp_bracestack.pop()
           bracemap[start] = position
           bracemap[position] = start
   return bracemap
 def buildlongcondmap(code):
   temp_bracestack, bracemap = [], {}
   for position, command in enumerate(code):
       if command == "<": temp_bracestack.append(position)
       if command == ">":
           start = temp_bracestack.pop()
           bracemap[start] = position
           bracemap[position] = start
   return bracemap
 def run_mawp(code,input_,debug=False, delay=0.1):
   formatted_input = list(input_)
   pos = 0
   stack = [1]
   squarebracemap = buildsquarebracemap(code)
   curlybracemap = buildcurlybracemap(code)
   longcondmap = buildlongcondmap(code)
   while True:
       char = code[pos]
       if debug:print(stack, char)
       if char == 'M':
           top = int(stack[-1])
           stack.pop(-1)
           sec = int(stack[-1])
           stack.pop(-1)
           stack.append(top+sec)
       elif char == 'A':
           top = int(stack[-1])
           stack.pop(-1)
           sec = int(stack[-1])
           stack.pop(-1)
           stack.append(abs(sec-top))
       elif char == 'W':
           top = int(stack[-1])
           stack.pop(-1)
           sec = int(stack[-1])
           stack.pop(-1)
           stack.append(top*sec)
       elif char == 'P':
           top = int(stack[-1])
           stack.pop(-1)
           sec = int(stack[-1])
           stack.pop(-1)
           stack.append(int(sec//top))
       elif char in ['0','1','2','3','4','5','6','7','8','9']:
           stack.append(char)
       elif char == '%':
           stack.pop(-1)
       elif char == '!':
           stack.append(stack[-1])
       elif char == ':':
           top = int(stack[-1])
           stack.pop(-1)
           print(str(top),end=)
       elif char == ';':
           top = int(stack[-1])
           stack.pop(-1)
           print(str(chr(top)),end=)
       elif char == '.':
           return 0
       elif char == ']':
           if stack[-1] != 0:
               pos = squarebracemap[pos]
       elif char == '[':
           if stack[-1] == 0:
               pos = squarebracemap[pos]
       elif char == ')':
           if stack[-1] == 0:
               pos = curlybracemap[pos]
       elif char == '(':
           if stack[-1] != 0:
               pos = curlybracemap[pos]
       elif char == '?':
           if stack[-1] != 0:
               pos += 1
       elif char == '|':
           stack.extend(ord(x) for x in formatted_input)
       elif char == '~':
           stack = list(reversed(stack))
       elif char == '<':
           if stack[-1] != 0:
               pos = longcondmap[pos]
       elif char == '_':
           stack.append(len(stack))
       pos += 1
       sleep(delay)

Which is run by calling run_mawp() with code and STDIN passed into it.

Example Programs

Hello, World!

The following program produces the classic Hello, World!

98W;55W4W1M;93W4W;93W4W;94W1M3W;58W4M;84W;98M5W2M;94W1M3W;99M1M6W;93W4W;55W4W;92M3W;.

Quine

Prints it's own source code.

481263753508787774753508787775350878777479153508787774793479133584793479159930~%52WWM/52WWM52WWM/[52WWM/]/[!:/]/[;]

Explanation:

The quine is essentially split into four parts.

The first part is the data, and is represented by the big blob of numbers in the start (excluding a 0). It represents the ASCII codes of the rest three parts of the code.

48126375350878777475350878777535087877747915350878777479347913358479347915993

The second part is the decoder. It turns the long stack of separate numbers into a smaller stack with multi-digit numbers. Note that if the ASCII for stack reversal `~` was two digit the decode could have been shortened significantly to just `0~%[52WWM/]`

0~%52WWM/52WWM52WWM/[52WWM/]
0~           Push a 0 and reverse stack
%            Remove the initial 1
52WWM        Multiply by 10 and add to next value  [8,5] ==> [58]
/            Cycle to next number
52WWM52WWM/  Do that two times and then cycle (special case for ~ ASCII 126)
[52WWM/]     Loop through the rest of the numbers with the same algo until 0

The third part loops over the stack and prints the first part as numbers WITHOUT destroying the data

/[!:/]
/            Cycle to next number
[            Start of loop
!:           Print top of stack as a number without destroying it
/]           Cycle to next number until 0 is reached

The last part loops over the stack and prints it as ASCII. Note that we don't have to preserve the data in stack any more, so it is shorter than the third part.

/[;]
/            Cycle to next number
[;]          Print as ASCII until reached 0

Quine 2

48923792915350878792773358929392915992930\%\[52WW\M!:\]\[;\]

Looping Counter

This program will output each integer from 1 to infinity in order until it is terminated

1[!:1M]

Truth Machine

Number Input:

@A{1A:.}1M[!:]

Character Input:

|68WA!~M1A?:?.[!:]

Odd or Even

%@_1A[1A~25WWM~]%[{1A{1M}<0:.>}2A]1:

Explanation

%@_1A[1A~25WWM~]% snippet used for inputting multi digit numbers
[                 loop if top of stack = 0
 {1A{1M}<0:.>}    if number-1=0 print 0 and end program
2A]               subtract 2 from the number
1:                once loop ends, print 1

Computational class

The computational class of MAWP 0.0 is unknown, since it only supports do...while loops, which can't be performed a translation with Volatile.

MAWP 0.1 is Turing-Complete, since it is possible to perform a translation with Volatile.

Volatile    MAWP
--------------------
~           1  (Any other constant will work in place as well)
+           M
-           A
*           W
/           P
:           !
.           !:
(...)       [...]

MAWP 1.1 is Turing-Complete by translation from Boolfuck (with tape extending command x, without I/O).

Boolf***        MAWP
---------------------------
@               \1/A
<               \
>               /
x               0
[               [
]               ]