diff --git a/Readme.org b/Readme.org index ff079da..57b1aa3 100644 --- a/Readme.org +++ b/Readme.org @@ -165,7 +165,38 @@ CURRENT VALUE AND/OR BODY: #+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 diff --git a/src/bin/main.rs b/src/bin/main.rs index e5a5a3e..8a08e96 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -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), diff --git a/src/stl/control.rs b/src/stl/control.rs index 64fc449..0b94f30 100644 --- a/src/stl/control.rs +++ b/src/stl/control.rs @@ -176,7 +176,6 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result { let mut result: Box = Box::new(Ctr::None); if !eval_forms.circuit(&mut |eval_form: &Ctr| -> bool { let res: Result, String>; - println!("let: {}", eval_form); if let Ctr::Seg(ref eval_tree) = eval_form { res = eval(&eval_tree, &mut localsyms); } else {