#ParentheticLisp
ParentheticLisp is an extension of cammckinnon/Parenthetic, which is a programming language that uses only (
and )
as code. All other characters are considered comments.
ParentheticLisp is fully backwards-compatibile with the original Parenthetic, but it adds the ability to read from STDIN as well as several standard library commands (mostly to deal with reading input). The vast majority of the code was still written by cammckinnon.
##Hello World
The following Parenthetic program prints "Hello World" followed by a trailing newline:
((()()())(()(((()))))((())()()()()()()()()()()()()()()()()()()()()()()()()()()()
()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()))((()()())(()(((())
))())((())()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()))((()()())(()(((())
))()())((()(())(())())((())()()()()()()()()()()()()()()()()()()()()()()()()()()(
)()()()()())))((()()())(()(((())))()()())((()(())(())())((())()()()()()()()()()(
))))((()(()))((()(())(())())((()(()))(()(((())))())((())()()()()()()())))((()(()
)(())())((()(()))(()(((()))))((())()()()())))((()(())(())())((()(()))(()(((())))
)((())()()()()()()()()()()())))((()(())(())())((()(()))(()(((()))))((())()()()()
()()()()()()())))((()(())(())())((()(()))(()(((()))))((())()()()()()()()()()()()
()()())))(()(((())))()())((()(())(())())((()(()))(()(((())))())((())()()()()()()
()()()()()()()()()()()()()()()())))((()(())(())())((()(()))(()(((()))))((())()()
()()()()()()()()()()()())))((()(())(())())((()(()))(()(((()))))((())()()()()()()
()()()()()()()()()()())))((()(())(())())((()(()))(()(((()))))((())()()()()()()()
()()()())))((()(())(())())((()(()))(()(((()))))((())()()())))(()(((())))()()()))
##Installation
-
Clone the repo, which includes an interpreter written in Python 2.7:
git clone git@github.com:habstinat/ParentheticLisp.git
-
Navigate to the ParentheticLisp directory and run the interpreter by typing:
python parenthetic.py [filename.par]
-
Or you can read input from stdin (terminated by Ctrl-D) by just running the program with no arguments:
python parenthetic.py
##Syntax
ParentheticLisp uses Lisp-style expressions, where parentheses enclose expressions:
(foo arg1 arg2)
Note that parenthetic programs with unmatched parentheses are invalid
###Integers
A sequence of n parenthesis sets can be used to represent the integer n. For example the following sequence could represent the number 3:
() () ()
In order to tell the interpreter that you want the sequence to represent an integer, you must pass it as an argument to the built-in (())
macro. The macro acts like a function that accepts parenthesis sequences and returns integers. For example, the following program prints 3.0 to the console:
(
integer macro
(())
3 sets of parentheses
() () ()
)
Output: 3.0
Or equivalently:
((()) ()()())
Output: 3.0
Note that it doesn't matter how the parentheses in the sequence are nested within each other. For instance the following Parenthetic program prints 5.0 to the console:
((()) ((())) () () )
Output: 5.0
###Symbols
A symbol is a sequence of parentheses that corresponds to some data or a function. For example, the symbol for the built-in multiplication function is ()(())
. Like with integers, there is a macro for interpreting parenthesis sequences as symbols. It is ()
.
For example, the following Parenthetic program prints 10 by using the multiplication function ()(())
to multiply 5 times 2:
(
multiply [note the use of the [] macro]
(() ()(()))
2
((()) ()())
5
((()) ()()()()())
)
Output: 10.0
Equivalent Lisp code:
(* 2 5)
It is also possible to define your own symbols, using the built-in 'define' function, whose symbol is ()()
.
Important: If you want to write portable ParentheticLisp code that doesn't shadow any standard library functions, present or future, you should begin your user-defined symbols with (((())))
. Any standard library functions that are added in the future will not start with (((())))
.
For example, the following code defines (())(())
as 6, then adds multiplies by 2 to get 12. Remember that all characters other than (
and )
characters are comments (including [
and ]
).:
define [[]][[]] as 6
(
define
(() ()())
[[]][[]]
(() (())(()))
6
((()) ()()()()()())
)
[[]][[]] * 2
(
multiply
(() ()(()))
[[]][[]]
(() (())(()))
2
((()) ()())
)
Output: 12.0
Equivalent Lisp code:
(define x 6)
(* x 2)
##Standard Library
Parenthetic has a built-in standard library that is available by default (no includes/library imports necessary):
###define
Symbol: ()()
For details on define and its usage, see the Syntax->Symbols section above.
###multiply, divide, subtract, add These math operations can be performed on one or more numbers. Here are their symbols:
- subtract:
(()())
- multiply:
()(())
- divide:
(())()
- add:
(())
. Note: You can also use add for concatenating characters/strings together (see the string section below).
Example:
(
plus
(() (()))
3
((()) ()()())
6
((()) ()()()()()())
)
Output: 9.0
Equivalent Lisp code:
(+ 3 6)
###lambda
Symbol: ()
Facilitates anonymous functions. Here's an example where we use define and lambda to create a function that takes in a number and adds 1 to it:
define a [][][] as a function that
takes in a number n and returns n + 1
(
define
(() ()())
[][][]
(() ()()())
(
lambda
(() ())
(
n [[]][]
(() (())())
)
n + 1
(
plus
(() (()))
n [[]][]
(() (())())
1
((()) ())
)
)
)
7 + 1
(
plus
(() ()()())
7
((()) ()()()()()()())
)
Output: 8.0
Equivalent Lisp code:
(define f
(lambda (n)
(+ n 1)))
(f 7)
###equal
Symbol: (())(())
Takes in two arguments. If they are equal, the True primitive is returned. Otherwise the False primitive is returned.
Example:
[equal 2 2]
(
equal
(() (())(()))
2
((()) ()())
2
((()) (()))
)
Output: True
Equivalent Lisp code:
(equal? 2 2)
###<=
Symbol: ()(())()
Takes in two numeric arguments a and b. If a <= b, the True primitive is returned. Otherwise the False primitive is returned.
Example:
[<= 3 4]
(
<=
(() ()(())())
3
((()) ()()())
4
((()) (())(()))
)
Output: True
Equivalent Lisp code:
(<= 3 4)
###if
Symbol: ()()()
Takes in three arguments: condition, then, and else. If condition is not false and not 0, the then argument is evaluated and returned. Otherwise, the else argument is evaluated and returned.
Example:
if 3 = 4, return 1, otherwise return 2
(
if
(() ()()())
[equal 3 4]
(
equal
(() (())(()))
3
((()) ()()())
4
((()) ((()))())
)
1
((()) ())
2
((()) ()())
)
Output: 2.0
Equivalent Lisp code:
(if (equal? 3 4) 1 2)
###not
Symbol: ()(()())
If the argument is neither 0.0 nor False, True is returned. Otherwise, False is returned.
Example:
[not [equal 1 1]]
(
not
(() ()(()()))
[equal 1 1]
(
equal
(() ()(())())
1
((()) ())
1
((()) ())
)
)
Output: False
Equivalent Lisp code:
(not (equal? 1 1))
###cons
Symbol: ((()))()
Takes in two arguments a and b and returns a pair (a, b)
.
Example:
(
cons
(() ((()))())
1
((()) ())
2
((()) ()())
)
Output: (1.0, 2.0)
Equivalent Lisp code:
(cons 1 2)
###car
Symbol: ((()))(())
Given a pair (a, b)
, returns a
.
Example:
(
car
(() ((()))(()))
(
cons
(() ((()))())
1
((()) ())
2
((()) ()())
)
)
Output: 1.0
Equivalent Lisp code:
(car (cons 1 2))
###cdr
Symbol: ((()))()()
(
cdr
(() ((()))()())
(
cons
(() ((()))())
1
((()) ())
2
((()) ()())
)
)
Output: 2.0
Equivalent Lisp code:
(cdr (cons 1 2))
###empty
Symbol: ((()))
empty exists to facilitate lists. We define a list as a pair such that applying cdr one or more times to the list will return empty. Note - empty is not a function; it can be accessed directly. When printed to the console, empty appears as ()
.
Example:
(() ((())))
Output: ()
Equivalent Lisp code:
(list)
###charsof
Symbol: ()()()()
charsof takes an object of type String as its parameter and outputs a linked list of characters in the order of that string. It is useful for iterating through user input generated by readline
.
Example:
Trim the first column from a line of user input
( exec
(() (())()(())) string
(
(() ((()))()()) cdr
(
(() ()()()()) charsof
( (() ()((()))) ) readline[]
)
)
)
Input: Hello
Output: ello
###reverse
Symbol: ()()(())
reverse takes in a list and outputs a copy of that list reversed. It does not reverse the list in-place.
Example:
Reverses a line of user input
( exec
(() (())()(())) string
(
(() ()()(())) reverse
(
(() ()()()()) charsof
( (() ()((()))) ) readline[]
)
)
)
Input: Hello
Output: olleH
###readline
Symbol: ()((()))
readline outputs a line read from stdin. Because readline uses mutable state, you would usually want to enclose it in an extra set of parentheses, as is done in the example.
Example:
Surrounds the input in parentheses
( exec
(() ()()) define
(() (((())))) 40 [[[[]]]]
(
(() ()(())) mult
((()) ()()()()()()()()()()) 10
((()) ()()()()) 4
)
)
( exec
(() ()()) define
(() (((())))()) input [[[[]]]] []
( (() ()((()))) ) readline[]
)
( exec
(() (())) concat
(
(() (())(())()) char
(() (((())))) 40
)
(() (((())))()) input
(
(() (())(())()) char
(
(() (())) plus
(() (((())))) 40
((()) ()) 1
)
)
)
Input Hello
Output (Hello)
###ord
Accepts one ascii character argument, and returns the corresponding integer.
Example:
Outputs the first input lowercase character as uppercase
( exec
(() (())(())()) char
(
(() (()())) minus
(
(() (())()()) ord
(
(() ((()))(())) car
(
(() ()()()()) charsof
( (() ()((()))) ) readline[]
)
)
)
(
(() ()(())) mult
((()) ()()()()()()()()) 8
((()) ()()()()) 4
)
)
)
Input: a
Output: A
###char
Symbol: (())(())()
Accepts one integer argument, and returns the corresponding ascii character.
Example:
(
char
(() (())(())())
33 [ascii value for '!']
((()) ()()()()()()()()()()
()()()()()()()()()()
()()()()()()()()()()
()()())
)
Output: !
###string
Symbol: (())()(())
Accepts a list of characters, and returns a string. string is useful for displaying messages.
Example:
define 97 for easy access to a and b
( define
(() ()())
97
(() (()()))
[+ 7 [* 9 10]]
(
(() (()))
((()) ()()()()()()())
(
(() ()(()))
((()) ()()()()()()()()())
((()) ()()()()()()()()()())
)
)
)
[string ['a', ['b', []]]]
(
string
(() (())()(()))
(
cons
(() ((()))())
a
(
(() (())(())())
(
(() (()))
((()) )
(() (()()))
)
)
(
cons
(() ((()))())
b
(
(() (())(())())
(
(() (()))
((()) ())
(() (()()))
)
)
empty
(() ((())))
)
)
)
Output: ab
Tip: You can also pass any combination of characters and strings into the add function (see above) to create strings.
##Error handling
If your program has a runtime error or a compiletime error the interpreter will print "Parenthesis Mismatch" to standard output and then exit.
##Test Suite
In the ./tests
folder there is a series of tests that check the interpreter for correctness.
python tests.py
You may find this useful if you wish to modify the interpreter's source code.
##Inspiration
The original Parenthetic language was inspired by a conversation with Lucas, who said that scheme looks like this: ())()()()))))(). Well, it does now!
Also the esoteric language Parenthesis Hell was a great inspiration.