Skip to content

Commit

Permalink
Add push function
Browse files Browse the repository at this point in the history
  • Loading branch information
vinc committed Dec 5, 2023
1 parent c85da44 commit 548aca4
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 12 deletions.
4 changes: 2 additions & 2 deletions doc/lisp.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ MOROS Lisp is a Lisp-1 dialect inspired by Scheme, Clojure, and Ruby!
- Arithmetic operations: `+`, `-`, `*`, `/`, `^`, `abs`, `mod`, `rem` (aliased to `%`)
- Trigonometric functions: `acos`, `asin`, `atan`, `cos`, `sin`, `tan`
- Comparisons: `>`, `<`, `>=`, `<=`, `=`
- Enumerable: `length` (aliased to `len`), `put`, `get`, `first`, `second`, `third`, `last`, `rest`, `slice`, `contains?`
- Enumerable: `length` (aliased to `len`), `push`, `put`, `get`, `first`, `second`, `third`, `last`, `rest`, `slice`, `contains?`
- String: `string.trim` and `string.split` (aliased to `str.trim` and `str.split`)
- List: `concat`, `chunks`, `sort`, `unique` (aliased to `uniq`), `min`, `max`
- Dict: `dict`
Expand Down Expand Up @@ -210,5 +210,5 @@ language and reading from the filesystem.
### Unreleased
- Add hexadecimal number literals
- Rename `nth` to `get`
- Add `empty?`, `reject`, `put` functions
- Add `empty?`, `reject`, `put`, and `push` functions
- Add `dict` type
1 change: 1 addition & 0 deletions src/usr/lisp/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub fn default_env() -> Rc<RefCell<Env>> {
data.insert("dict".to_string(), Exp::Primitive(primitive::lisp_dict));
data.insert("get".to_string(), Exp::Primitive(primitive::lisp_get));
data.insert("put".to_string(), Exp::Primitive(primitive::lisp_put));
data.insert("push".to_string(), Exp::Primitive(primitive::lisp_push));

// Setup autocompletion
*FUNCTIONS.lock() = data.keys().cloned().chain(BUILT_INS.map(String::from)).collect();
Expand Down
8 changes: 6 additions & 2 deletions src/usr/lisp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,11 @@ fn test_lisp() {
assert_eq!(eval!("(get (dict \"a\" 1 \"b\" 2 \"c\" 3) \"d\")"), "()");

// put
assert_eq!(eval!("(put \"Hell\" \"o\")"), "\"Hello\"");
assert_eq!(eval!("(put (list 1 2) 3)"), "(1 2 3)");
assert_eq!(eval!("(put (dict \"a\" 1 \"b\" 2) \"c\" 3)"), "(dict \"a\" 1 \"b\" 2 \"c\" 3)");
assert_eq!(eval!("(put (list 1 3) 1 2)"), "(1 2 3)");
assert_eq!(eval!("(put \"Heo\" 2 \"ll\")"), "\"Hello\"");

// push
assert_eq!(eval!("(push \"Hell\" \"o\")"), "\"Hello\"");
assert_eq!(eval!("(push (list 1 2) 3)"), "(1 2 3)");
}
29 changes: 24 additions & 5 deletions src/usr/lisp/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,30 +545,49 @@ pub fn lisp_get(args: &[Exp]) -> Result<Exp, Err> {
}

pub fn lisp_put(args: &[Exp]) -> Result<Exp, Err> {
ensure_length_gt!(args, 0);
ensure_length_eq!(args, 3);
match &args[0] {
Exp::Dict(dict) => {
ensure_length_eq!(args, 3);
let mut dict = dict.clone();
let key = format!("{}", args[1]);
let val = args[2].clone();
dict.insert(key, val);
Ok(Exp::Dict(dict))
}
Exp::List(list) => {
ensure_length_eq!(args, 2);
let i = usize::try_from(number(&args[1])?)?;
let val = args[2].clone();
let mut list = list.clone();
list.insert(i, val);
Ok(Exp::List(list))
}
Exp::Str(s) => {
let i = usize::try_from(number(&args[1])?)?;
let v: Vec<char> = string(&args[2])?.chars().collect();
let mut s: Vec<char> = s.chars().collect();
s.splice(i..i, v);
let s: String = s.into_iter().collect();
Ok(Exp::Str(s))
}
_ => expected!("first argument to be a dict, a list, or a string")
}
}

pub fn lisp_push(args: &[Exp]) -> Result<Exp, Err> {
ensure_length_eq!(args, 2);
match &args[0] {
Exp::List(list) => {
let mut list = list.clone();
let val = args[1].clone();
list.push(val);
Ok(Exp::List(list))
}
Exp::Str(s) => {
ensure_length_eq!(args, 2);
let mut s = s.clone();
let val = string(&args[1])?;
s.push_str(&val);
Ok(Exp::Str(s))
}
_ => expected!("first argument to be a dict, a list, or a string")
_ => expected!("first argument to be a a list or a string")
}
}
10 changes: 7 additions & 3 deletions www/lisp.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,21 @@ <h3>Primitive Operators</h3>
<li>Arithmetic operations: <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>^</code>, <code>abs</code>, <code>mod</code>, <code>rem</code> (aliased to <code>%</code>)</li>
<li>Trigonometric functions: <code>acos</code>, <code>asin</code>, <code>atan</code>, <code>cos</code>, <code>sin</code>, <code>tan</code></li>
<li>Comparisons: <code>&gt;</code>, <code>&lt;</code>, <code>&gt;=</code>, <code>&lt;=</code>, <code>=</code></li>
<li>Enumerable: <code>length</code> (aliased to <code>len</code>), <code>nth</code>, <code>first</code>, <code>second</code>, <code>third</code>, <code>last</code>, <code>rest</code>, <code>slice</code></li>
<li>Enumerable: <code>length</code> (aliased to <code>len</code>), <code>push</code>, <code>put</code>, <code>get</code>, <code>first</code>, <code>second</code>, <code>third</code>, <code>last</code>, <code>rest</code>, <code>slice</code>, <code>contains?</code></li>
<li>String: <code>string.trim</code> and <code>string.split</code> (aliased to <code>str.trim</code> and <code>str.split</code>)</li>
<li>List: <code>concat</code>, <code>chunks</code>, <code>sort</code>, <code>unique</code> (aliased to <code>uniq</code>), <code>min</code>, <code>max</code></li>
<li>Dict: <code>dict</code></li>
<li>File: <code>file.size</code>, <code>file.open</code>, <code>file.close</code>, <code>file.read</code>, <code>file.write</code></li>
</ul>

<h3>Core Library</h3>

<ul>
<li><code>nil</code>, <code>nil?</code>, <code>list?</code></li>
<li><code>nil</code>, <code>nil?</code>, <code>list?</code>, <code>empty?</code></li>
<li><code>boolean?</code> (aliased to <code>bool?</code>), <code>string?</code> (aliased to <code>str?</code>), <code>symbol?</code> (aliased to <code>sym?</code>), <code>number?</code> (aliased to <code>num?</code>)</li>
<li><code>function?</code> (aliased to <code>fun?</code>), <code>macro?</code> (aliased to <code>mac?</code>)</li>
<li><code>first</code>, <code>second</code>, <code>third</code>, <code>rest</code></li>
<li><code>map</code>, <code>reduce</code>, <code>reverse</code> (aliased to <code>rev</code>), <code>range</code>, <code>filter</code>, <code>intersection</code></li>
<li><code>map</code>, <code>reduce</code>, <code>reverse</code> (aliased to <code>rev</code>), <code>range</code>, <code>filter</code>, <code>reject</code>, <code>intersection</code></li>
<li><code>not</code>, <code>and</code>, <code>or</code></li>
<li><code>let</code></li>
<li><code>string.join</code> (aliased to <code>str.join</code>), <code>lines</code>, <code>words</code>, <code>chars</code></li>
Expand Down Expand Up @@ -254,6 +255,9 @@ <h3>Unreleased</h3>

<ul>
<li>Add hexadecimal number literals</li>
<li>Rename <code>nth</code> to <code>get</code></li>
<li>Add <code>empty?</code>, <code>reject</code>, <code>put</code>, and <code>push</code> functions</li>
<li>Add <code>dict</code> type</li>
</ul>
<footer><p><a href="/">MOROS</a></footer>
</body>
Expand Down

0 comments on commit 548aca4

Please sign in to comment.