complete all introductory documentation, except for the Easy Patterns
section Also, removed some stray debug lines and added a printed newline inbetween prompt and output
This commit is contained in:
parent
67af8bbd47
commit
20821057f2
3 changed files with 126 additions and 13 deletions
136
Readme.org
136
Readme.org
|
|
@ -165,7 +165,38 @@ CURRENT VALUE AND/OR BODY:
|
|||
<builtin>
|
||||
#+END_SRC
|
||||
|
||||
*** TODO Quote and Eval
|
||||
*** Quote and Eval
|
||||
As stated previously: Lisp, and consequently Relish, is homoiconic. This means that code can be passed around (and modified) as data.
|
||||
This allows us to write self programming programs, or construct entire procedures on the fly. The primary means to do so are with *quote* and *eval*.
|
||||
The *quote* function allows data (code) to be passed around without evaluating it. It is used to pass unevaluated code around as data that can then be evaluated later.
|
||||
To be specific, typing ~(a)~ usually results in a symbol lookup for ~a~, and then possibly even a function call. However, if we *quote* ~a~, we can pass around the symbol itself:
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
(quote a) ;; returns the symbol a
|
||||
(quote (add 1 2)) ;; returns the following tree: (add 1 2)
|
||||
#+END_SRC
|
||||
|
||||
We can use this to build structures that evaluate into new data:
|
||||
#+BEGIN_SRC lisp
|
||||
(let ((mylist (quote (add))) ;; store a list starting with the add function
|
||||
(myiter 0)) ;; store an iterator starting at 0
|
||||
(while (lt? myiter 4) ;; loop until the iterator >= 4
|
||||
(inc myiter) ;; increment the iterator
|
||||
(def mylist '' (cons mylist myiter)) ;; add to the list
|
||||
(echo mylist)) ;; print the current state of the list
|
||||
(echo (eval mylist))) ;; print the eval result
|
||||
#+END_SRC
|
||||
|
||||
Notice the final body in the let form: ~(echo (eval mylist))~
|
||||
The above procedure outputs the following:
|
||||
#+BEGIN_EXAMPLE
|
||||
(add 1)
|
||||
(add 1 2)
|
||||
(add 1 2 3)
|
||||
(add 1 2 3 4)
|
||||
10
|
||||
#+END_EXAMPLE
|
||||
|
||||
*** Lambda
|
||||
Another form of homoiconicity is the *anonymous function*.
|
||||
This is a nameless function being passed around as data.
|
||||
|
|
@ -194,10 +225,96 @@ Here is the lambda bound to a variable inside a let statement:
|
|||
(adder 1 2)) ;; local var (lambda) called here
|
||||
#+END_SRC
|
||||
|
||||
*** TODO Defining variables and functions
|
||||
**** TODO Anatomy
|
||||
**** TODO Naming conventions
|
||||
**** TODO Undefining variables and functions
|
||||
*** Defining variables and functions
|
||||
In Relish, both variables and functions are stored in a table of symbols.
|
||||
All Symbols defined with ~def~ are *GLOBAL*. The only cases when symbols are local is when they are defined as part of *let* forms or as arguments to functions.
|
||||
In order to define a symbol, the following arguments are required:
|
||||
- A name
|
||||
- A docstring (absolutely required)
|
||||
- A list of arguments (only needed to define a function)
|
||||
- A value
|
||||
|
||||
Regarding the *value*: A function may be defined with several trees of code to execute.
|
||||
In this case, the value derived from the final form in the function will be returned.
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
(def my-iter 'an iterator to use in my while loop' 0) ;; a variable
|
||||
(def plus-one 'adds 1 to a number' (x) (add 1 x)) ;; a function
|
||||
(def multi-func 'example of multi form function'
|
||||
(x y) ;; args
|
||||
(inc my-iter) ;; an intermediate calculation
|
||||
(add x y my-iter)) ;; the final form of the function. X+Y+MYITER is returned
|
||||
#+END_SRC
|
||||
|
||||
Make sure to read the *Configuration* section for information on how symbols are linked to environment variables.
|
||||
|
||||
**** Naming conventions
|
||||
- Symbol names are case sensitive
|
||||
- Symbols may contain alphanumeric characters
|
||||
- Symbols may contain one or more of the following: - _ ?
|
||||
- The idiomatic way to name symbols is ~all-single-case-and-hyphenated~
|
||||
|
||||
**** Undefining variables and functions
|
||||
Removing a symbol consists of a call to ~def~ with no additional arguments:
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
(def my-iter 'an iterator' 0)
|
||||
(inc my-iter) ;; my-iter = 1
|
||||
(def my-iter) ;; removes my-iter
|
||||
(inc my-iter) ;; UNDEFINED SYMBOL ERROR
|
||||
#+END_SRC
|
||||
|
||||
** Builtin functions
|
||||
As opposed to listing every builtin function here, it is suggested to the user to do one of two things:
|
||||
- Call ~env~ from a fresh shell: ~(env)~
|
||||
This will output all variables and functions defined
|
||||
- Read the std library declaration code:
|
||||
file:src/stl.rs
|
||||
|
||||
** Documentation
|
||||
*** Tests
|
||||
Most of the tests evaluate small scripts (single forms) and check their output.
|
||||
Perusing them may yield answers on all the cases a given builtin can handle.
|
||||
file:tests/
|
||||
|
||||
*** Help function
|
||||
Relish is self documenting. The *help* function can be used to inspect any variable or function.
|
||||
It will show the name, current value, docstring, arguments, and definition of any builtin or user defined function or variable.
|
||||
#+BEGIN_EXAMPLE
|
||||
> (help my-adder)
|
||||
NAME: my-adder
|
||||
|
||||
ARGS: 2 args of any type
|
||||
|
||||
DOCUMENTATION:
|
||||
|
||||
adds two numbers
|
||||
|
||||
CURRENT VALUE AND/OR BODY:
|
||||
args: x y
|
||||
form: ((add x y))
|
||||
#+END_EXAMPLE
|
||||
#+BEGIN_EXAMPLE
|
||||
> (help CFG_RELISH_ENV) <
|
||||
NAME: CFG_RELISH_ENV
|
||||
|
||||
ARGS: (its a variable)
|
||||
|
||||
DOCUMENTATION:
|
||||
|
||||
my env settings
|
||||
|
||||
CURRENT VALUE AND/OR BODY:
|
||||
true
|
||||
#+END_EXAMPLE
|
||||
|
||||
Every single symbol in Relish can be inspected in this way, unless some third party developer purposefully left a docstring blank.
|
||||
|
||||
*** Snippets directory
|
||||
The *snippets directory* may also yield some interesting examples.
|
||||
Within it are several examples that the authors and maintainers wanted to keep around but didnt know where.
|
||||
It is sort of like a lint roller.
|
||||
It also contains considerably subpar implementations of Relish's internals that are kept around for historical reasons.
|
||||
|
||||
** Easy patterns
|
||||
This section can serve as a sort of cookbook for a user who is new to leveraging LISP languages or unsure of where to start with ~relish~.
|
||||
|
|
@ -225,6 +342,7 @@ The while-let pattern can be used for many purposes. Above it is used to iterate
|
|||
*** TODO short-circuit guard
|
||||
- circuit example
|
||||
- while-not-circuit-do-more-work
|
||||
*** TODO shell capabilities check
|
||||
*** let destructuring
|
||||
~let~ is very useful for destructuring complex return types. If you have a function that may return a whole list of values you can then call it from ~let~ to consume the result data.
|
||||
In this example a let form is used to destructure a call to ~head~. ~head~ returns a list consisting of ~(first-element rest-of-list)~ (for more information see ~(help head)~).
|
||||
|
|
@ -256,12 +374,7 @@ Alternatively this combination can be used to process flags in a script or appli
|
|||
(process-flag myflag)
|
||||
())
|
||||
#+END_SRC
|
||||
** TODO Builtin functions
|
||||
*** TODO Env function
|
||||
** TODO Documentation
|
||||
*** TODO Tests
|
||||
*** TODO Help function
|
||||
*** TODO Snippets directory
|
||||
|
||||
|
||||
** Configuration
|
||||
By default Relish will read from ~/.relishrc for configuration, but the default shell will also accept a filename from the RELISH_CFG_FILE environment variable.
|
||||
|
|
@ -363,6 +476,7 @@ This contains any executable target of this project. Notably the main shell file
|
|||
Note: this section will not show the status of each item unless you are viewing it with a proper orgmode viewer.
|
||||
Note: this section only tracks the state of incomplete TODO items. Having everything on here would be cluttered.
|
||||
|
||||
*** TODO set function
|
||||
*** TODO list contains via circuit
|
||||
*** TODO Input function
|
||||
*** TODO Lex function
|
||||
|
|
|
|||
|
|
@ -112,8 +112,8 @@ fn main() -> ! {
|
|||
let user_doc = rl.read_line(&readline_prompt).unwrap();
|
||||
match user_doc {
|
||||
Signal::Success(line) => {
|
||||
println!(""); // add a new line before output gets printed
|
||||
let l = line.as_str().to_owned();
|
||||
|
||||
match lex(&l) {
|
||||
Ok(a) => match eval(&a, &mut syms) {
|
||||
Ok(a) => println!("{}", a),
|
||||
|
|
|
|||
|
|
@ -176,7 +176,6 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
|||
let mut result: Box<Ctr> = Box::new(Ctr::None);
|
||||
if !eval_forms.circuit(&mut |eval_form: &Ctr| -> bool {
|
||||
let res: Result<Box<Ctr>, String>;
|
||||
println!("let: {}", eval_form);
|
||||
if let Ctr::Seg(ref eval_tree) = eval_form {
|
||||
res = eval(&eval_tree, &mut localsyms);
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue