Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
* YALL DOCUMENTATION ** Demo Video https://youtu.be/X38Ry1Jk7FU ** Installation *** Dependencies To install YALL you will need ~cmake~ installed. *** Install Process To build the project and install it in you ~/.local/bin/ Run the command #+begin_src cmake -H. -Btmp -DCMAKE_INSTALL_PREFIX =~/.local/bin/ #+end_src Then #+begin_src cmake --build tmp --clean-first --target install #+end_src ** YALL a simple extensible lisp dialect This program consists of two parts 1 the demo script which feeds some example code into a non interactive YALL process. The other part is an the yall executable it's self. you can run it interactively with #+begin_src lisp -i #+end_src or #+begin_src lisp --interactive #+end_src If you want to pass it input from an existing file run #+begin_src lisp < file_to_run.scm #+end_src Since yall is heavily inspired by scheme it's recommended to set your editor to its' scheme or at least lisp mode for better syntax highlighting. ** Functions Available In YALL *** + adds 2 values together and returns the result as an integer #+begin_src scheme (+ <symboli-expression> <symboli-expression>) #+end_src *** - subtract the first argument from the second argument and returns the result as an integer #+begin_src scheme (- <symboli-expression> <symboli-expression>) #+end_src *** * multiply 2 values together and returns the result as an integer #+begin_src scheme (* <symboli-expression> <symboli-expression>) #+end_src *** = Compares 2 integers for equivalence and returns the result as a boolean #+begin_src scheme (= <symboli-expression> <symboli-expression>) #+end_src *** eq Compares 2 expressions for equivalence and returns the result as a boolean (note that all functions equivalent) #+begin_src scheme (eq <symboli-expression> <symboli-expression>) #+end_src *** if Takes 2 or 3 arguments. the first being a condition that results in a boolean the second being the expression to return if this is true and the optional third will be returned if it is false. If no third argument is provided and the condition is evaluated to be #f then the #f is returned. #+begin_src scheme (if <condition> <then> <else>) #+end_src *** list Takes a variable number of arguments of at least one and returns the result as a list. #+begin_src scheme (list <symboli-expression>+) #+end_src *** append Takes 2 lists and appends them then returns the result as a list. #+begin_src scheme (append <list> <list>) #+end_src *** cons Takes 2 arguments and produces either a cons cell or a list. If the second argument is a list then it will return a list with the first argument at the front of the list Otherwise a cons cell is returned with the first and second arguments as it's contents. #+begin_src scheme (cons <symbolic-expression> <symbolic-expression>) #+end_src *** car Takes one argument of either a cons cell or a list and returns the first element. #+begin_src scheme (car <cons-or-list>) #+end_src *** cdr Takes one argument of either a cons cell or a list and returns everything other than the first argument. #+begin_src scheme (cdr <cons-or-list>) #+end_src *** sleep Takes one argument of an integer n and halts the YALL for n seconds the number of seconds is then returned. #+begin_src scheme (sleep <int>) #+end_src *** print Takes a symbolic expression and prints the string representation. It's argument is then used as it's returned value. #+begin_src scheme (print <expression>) #+end_src ** Supported Types *** Supported Symbols Symbols can contain a series of letters, numbers and dashes however the first character must always be a letter. The exception to this is the built in symbols *, -, and + The regular expression for this would look something like [a-Z]([a-Z]|-|[0-9])+ *** Numbers Numbers can be any valid C++ int. There is no attempt by YALL to handle integer overflow. *** Booleans The only supported booleans are #t for true and #f for false *** Containers **** Lists Lists in YALL can be created with the list function (list + 2 3) => (#<YALL Function> 2 3) Alternatively quoting an expression will also create a list without evaluating it's contents (quote (+ 2 3)) => (+ 2 3) **** Cons Cells Lists in YALL can be created with the cons function (cons 1 2) => (1 . 2) Alternatively quoting a dotted expression to create a cons cell without evaluating it's contents (quote (+ . 2)) => (+ . 2) * Language Overview ** What is YALL? YALL is a lisp dialect inspired by Scheme ** How does it work YALL can be ran interactively and non interactively to run it interactively call it with the ~-i~ We can now begin evaluating expressions ** What are expressions Expressions are a made up of what are known as symbolic expressions. an expression consists of to parentheses Here is an example #+begin_src scheme (+ 1 2) #+end_src The first argument is a function call and the others are it's arguments The when ran this evaluates to #+begin_src 3 #+end_src ** Functions YALL has a single namespace for both functions and variables so you can store and call other functions. functions are created with the lambda keyword followed by a list of arguments and th body of the function #+begin_src scheme (lambda (argOne argTwo) ; arguments (+ argOne argTwo)) ; body #+end_src We can store values using define #+begin_src scheme (define double (lambda (a) (* a 2))) #+end_src #+RESULTS: Then we can call the function just like any built in one #+begin_src scheme (double 10) #+end_src #+RESULTS: : 20 Since functions act as variables you can also pass them as arguments This will partially apply the first argument #+begin_src scheme (define curry (lambda (fn arg) (lambda (y) (fn 1 y)))) #+end_src #+begin_src scheme (curry + 1) ; a function #+end_src #+begin_src scheme ((curry + 1) 2) #+end_src #+RESULTS: : 3 ** Definitions are limited Unfortunately a current limitation of YALL is that bindings can not be back referenced. #+begin_src scheme (define caller (lambda (x) (x 1))) #+end_src #+begin_src scheme (define isOne (lambda (num) (= num 1))) #+end_src #+begin_src scheme (caller isOne) #+end_src will work but #+begin_src scheme (define caller (lambda () (isOne 1))) #+end_src #+begin_src scheme (define isOne (lambda (num) (= num 1))) #+end_src #+begin_src scheme (caller) #+end_src Will fail For this same reason recursion is not possible. ** let In addition can define new lexically scoped blocks using ~let~ #+begin_src scheme (let ((a 1) (b 2)) (+ a b)) #+end_src #+RESULTS: : 3 Just like anything else you can also define functions in let declarations. ** Code as data YALL also allows for code to be used as data. Use the quote keyword to prevent evaluation of an expression. #+begin_src scheme (quote (+ 1 2)) #+end_src Then you can access the contents with the functions ~car~ and ~cdr~ You can think of them as the same thing as first and rest #+begin_src scheme (car (quote (+ 1 2))) #+end_src Just due to the time constants of the course proper meta programming (since you can not unquote an expression) is not fully supported since there is now. for example #+begin_src scheme ((car (quote (+ 1 2))) 1 2) #+end_src will fail to function since the ~+~ will remain quoted. However accessing numbers will function as expected #+begin_src scheme (+ (car (quote (1 2))) 3) #+end_src For this reason I included the ~list~ function but this will allow for ~+~ to evaluate to a function #+begin_src scheme ((car (list + 1 2)) 1 2) #+end_src ** YALL supports conditional logic #t is for true #f is for false The only built in conditional logic is ~if~ #+begin_src scheme (if (= 1 1) (quote (yes they are)) (quote (no they are not))) #+end_src With this most common logic can be defined #+begin_src scheme (define not (lambda (condition) (if condition #f #t))) #+end_src #+begin_src scheme (not (= 1 1)) #+end_src you can compare symbols with ~eq~ Note that to compare symbols they need to be quoted otherwise their values will be compared src scheme (eq (quote a) (quote b)) #+end_src src scheme (eq (quote a) (quote a)) #+end_src #+begin_src scheme (eq 1 1) #+end_src ** Acknowledgments Since this was my first attempt at writing a proper parser lot's of research was necessary to get started. I would like to thank the Make a Lisp Project in particular the https://github.com/kanaka/mal/blob/master/process/guide.md#step1 Which gave me a good Idea of what was needed to write a proper tokenizer and parser. No code was used from the project but multiple ideas inspired my reader implementation. Since my language (scheme like) is quite different from the one created in MAL (clojure like) only the core ideas of writing a lisp parser where able to be reused.