Parable
Parable is a Lisp interpreter, at the moment being bootstrapped from Python. You can take a look at the current development roadmap to learn more about Parable.
To get a REPL, just clone the repository and run ./repl.py
.
A Python-based Lisp interpreter.
License: GNU General Public License v3.0
Parable is a Lisp interpreter, at the moment being bootstrapped from Python. You can take a look at the current development roadmap to learn more about Parable.
To get a REPL, just clone the repository and run ./repl.py
.
Don't forget to test for too few arguments in case of the presence of &rest arguments in functions, normal macros and macros with destructuring argument lists with &rest in sublists.
Add case macro like this:
(case (form)
(case1 value1)
(case2 value2)
(case3 value3)
[default])
When a read or eval error occurs, it's very useful to have the line number (and perhaps the column number) of the error.
As specified in the new roadmap, &
is to be used instead of &rest
for marking the rest argument.
Add a macro expression in this form:
(mac (params) expression)
This can be called exactly like a lambda expression; the only difference is that the arguments are passed to the macro unevaluated.
Update the README to contain the following:
#t
and #f
are, at the moment, special symbols that evaluate to true and false. This means if we need a list of booleans we cannot use '(#f #f #t #f)
; we can only use (list #f #f #t #f)
so that all items are actually evaluated.
Making #t
and #f
reader literals fixes this. We need to define a Boolean class as the reader's equivalent of bool (like we've done so far for list, int and str). The reader then directly reads a True
or False
.
Write tests for the error reporter to check if it indeed reports the errors and highlights the problematic parts correctly.
eq
and atom
primitives return a string "t" instead of the symbol t. This has gone unnoticed since in the test cases we check for the result not being nil, which is technically correct but not what we intend it. For now, perhaps we'd better update the tests so that they explicitly check for the symbol t and then fix the problem.
A loader, reads all the forms in a file, macro-expands them, and if they become define
forms adds them to an environment dictionary. The load returns this dictionary.
define
forms are similar to those found in Scheme: (define name value)
. These add values to the compile-time environment.
Make it so we can either quiet the test runner (nothing displayed), have it run in normal verbosity (perhaps like the python unittest runner which shows a single character for each test) or have it run in verbose mode (where it shows us what tests is just running, what finished running, the status, etc.).
Currently the reader and the evaluator simply print an error message and exit immediately. Throwing exceptions like ReadError and EvalError seems to be a better option.
Current pretty printer is not, well, that pretty! Write one that at least prints in multi-line and indents the forms properly.
The current implementation of backquote does not support nested backquotes. Implement this feature. See issue #4 for more information.
In a purely symbolic Lisp, that is one with only lists and symbols, the atom
primitive can be used to detect the type of a given value. This does not work however in a Lisp like Parable that has other data types, too (numbers and strings). We can replace the atom
primitive with a typeof
primitive which returns the type of a given value as one of the symbols: symbol
, list
, str
and int
. With this primitive available, we can add atom
(as well as other type predicates) as a function in stdlib.
Add a +
function to stdlib that adds any number of integers passed to it.
Symbols that begin with a colon (like :foo
) are called keywords. Keywords are self-evaluating.
Add integer and string types and their literal representations (quoted strings and decimal integers).
Add a length
function to stdlib that returns the length of a list.
Extend load.py CLI to recognize the following arguments:
Currently the scope of variables dynamic. Make it lexical (static). To do this, we simply need to store the environment of the body of the function inside the Function object itself at the time it is instantiated. Later when we want to call the function, we use the environment stored in the Function object itself, rather than the current environment. The same must be done for macros, too.
It should be an error for a macro or function to have two or more arguments with the same name. Write a test case for this and fix it.
We're gonna need one of those. Reading code in Python lists is painful to the eyes.
Make it so that foo:bar
(in which foo
and bar
are symbols both evaluating to functions) evaluates to the composition of the two functions. Any number of functions can be composed this way.
Add a macro called backquote
that excepts one argument and returns it unaltered except for any form (unquote form)
in it which will be replaced with the result of evaluating form
. Also occurrences of (unquote-list form)
forms will result in the evaluation of form
(which must be a list) expanded in-place. The unquote
and unquote-splicing
forms must be searched for and replaced in the passed argument recursively.
Make it so that (n lst)
in which n
evaluates to an integer and lst
evaluates to a list, returns the nth element of the list.
At the moment, the append
function in stdlib accepts exactly two arguments. Make it so that it can accept any number of arguments like in Common Lisp.
Destructuring argument lists can increase readability of macro definitions.
The test runner can show the forms that evaluated to false in the test suite.
As the current roadmap indicates, a side effect having lists as the primary data structure instead of cons is that first, rest and prep are better names than car, cdr and cons (although I really like those!).
Anything except a Symbol in an argument list should not be allowed (destructuring macro argument lists can contain lists, too, but those must recursively contain either lists or symbols). Add a test case for this.
We need to fix #9 before we can add this test case.
Write test cases for all errors raised.
The apply primitive receives a function and a list and calls the function with the values in the given list as arguments.
Writing (quote form)
is tedious and verbose. All Lisp implementations let's one write it as 'form
which is both more readable and easier to type. Add this notation.
We probably need a more advanced reader to add this feature.
Write the test case, see how the program behaves and fix the behavior if necessary.
Update the evaluator to evaluate the special symbol nil
as ()
.
If the last argument of a function or a macro is &rest
, it should capture any number of arguments from that point on as a list.
type is just cooler than typeof!
Extend the reader so that it accepts comments. Single line comments are sufficient at this point. Anything that appears after a semicolon should be considered a comment.
Add a -
function that if passed one integer, negates it, otherwise subtracts any number of integers sequentially.
All the functions and macros defined in stdlib need tests.
Backslash character should be able to escape characters in a string.
'(a b c)
is more readable than (quote (a b c))
. Now that we have this feature, we'd better use it in the tests.
Currently, you can't pass primitives as functions; for example (mapf car '((1) (2) (3)))
won't work since there is no car
function. We can add function versions of these to stdlib. For example:
(defun car (lst)
(car lst))
Add a *
function to stdlib that multiplies any number of integers.
After the typeof
primitive (see issue #23) is implemented we can add a polymorphic =
function. It must:
eq
returns true.=
returns true for all elements.The README should contain a short section describing how to run a simple Parable program.
Implement an assoc
function that looks up for an item in an association list. An association list is a list of the form (key1 value1 key2 value2 ... keyn valuen)
. The assoc
function receives a key and returns its associated value. If the key does not exist in the list, an error is raised.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.