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>
|
<builtin>
|
||||||
#+END_SRC
|
#+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
|
*** Lambda
|
||||||
Another form of homoiconicity is the *anonymous function*.
|
Another form of homoiconicity is the *anonymous function*.
|
||||||
This is a nameless function being passed around as data.
|
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
|
(adder 1 2)) ;; local var (lambda) called here
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
*** TODO Defining variables and functions
|
*** Defining variables and functions
|
||||||
**** TODO Anatomy
|
In Relish, both variables and functions are stored in a table of symbols.
|
||||||
**** TODO Naming conventions
|
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.
|
||||||
**** TODO Undefining variables and 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
|
** 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~.
|
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
|
*** TODO short-circuit guard
|
||||||
- circuit example
|
- circuit example
|
||||||
- while-not-circuit-do-more-work
|
- while-not-circuit-do-more-work
|
||||||
|
*** TODO shell capabilities check
|
||||||
*** let destructuring
|
*** 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.
|
~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)~).
|
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)
|
(process-flag myflag)
|
||||||
())
|
())
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
** TODO Builtin functions
|
|
||||||
*** TODO Env function
|
|
||||||
** TODO Documentation
|
|
||||||
*** TODO Tests
|
|
||||||
*** TODO Help function
|
|
||||||
*** TODO Snippets directory
|
|
||||||
|
|
||||||
** Configuration
|
** 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.
|
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 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.
|
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 list contains via circuit
|
||||||
*** TODO Input function
|
*** TODO Input function
|
||||||
*** TODO Lex function
|
*** TODO Lex function
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,8 @@ fn main() -> ! {
|
||||||
let user_doc = rl.read_line(&readline_prompt).unwrap();
|
let user_doc = rl.read_line(&readline_prompt).unwrap();
|
||||||
match user_doc {
|
match user_doc {
|
||||||
Signal::Success(line) => {
|
Signal::Success(line) => {
|
||||||
|
println!(""); // add a new line before output gets printed
|
||||||
let l = line.as_str().to_owned();
|
let l = line.as_str().to_owned();
|
||||||
|
|
||||||
match lex(&l) {
|
match lex(&l) {
|
||||||
Ok(a) => match eval(&a, &mut syms) {
|
Ok(a) => match eval(&a, &mut syms) {
|
||||||
Ok(a) => println!("{}", a),
|
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);
|
let mut result: Box<Ctr> = Box::new(Ctr::None);
|
||||||
if !eval_forms.circuit(&mut |eval_form: &Ctr| -> bool {
|
if !eval_forms.circuit(&mut |eval_form: &Ctr| -> bool {
|
||||||
let res: Result<Box<Ctr>, String>;
|
let res: Result<Box<Ctr>, String>;
|
||||||
println!("let: {}", eval_form);
|
|
||||||
if let Ctr::Seg(ref eval_tree) = eval_form {
|
if let Ctr::Seg(ref eval_tree) = eval_form {
|
||||||
res = eval(&eval_tree, &mut localsyms);
|
res = eval(&eval_tree, &mut localsyms);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue