Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve lisp #455

Merged
merged 10 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions doc/lisp.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ Rewrite parts of the code and add new functions and examples.
- `splice` (with the `@` syntax)
- `atom` (aliased to `atom?`)
- `eq` (aliased to `eq?`)
- `car` (aliased to `first`)
- `cdr` (aliased to `rest`)
- `head` (aliased to `car`)
- `tail` (aliased to `cdr`)
- `cons`
- `if`
- `cond`
Expand All @@ -78,12 +78,13 @@ Rewrite parts of the code and add new functions and examples.
- `regex-find`
- `system`

- Arithmetic operations: `+`, `-`, `*`, `/`, `%`, `^`
- Arithmetic operations: `+`, `-`, `*`, `/`, `%`, `^`, `abs`
- Trigonometric functions: `acos`, `asin`, `atan`, `cos`, `sin`, `tan`
- Comparisons: `>`, `<`, `>=`, `<=`, `=`
- File IO: `read-file`, `read-file-bytes`, `write-file-bytes`, `append-file-bytes`
- List: `chunks`, `slice`, `sort`, `uniq`, `length`
- List: `chunks`, `sort`, `unique`, `min`, `max`
- String: `trim`, `split`
- Enumerable: `length`, `nth`, `first`, `second`, `third`, `last`, `rest`, `slice`

### Core Library
- `nil`, `nil?`, `eq?`
Expand Down Expand Up @@ -125,7 +126,7 @@ with the following content:

(println
(if (nil? args) "Usage: fibonacci <num>"
(fibonacci (string->number (car args)))))
(fibonacci (string->number (head args)))))
```

Would produce the following output:
Expand Down
6 changes: 5 additions & 1 deletion dsk/lib/lisp/alias.lsp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
(define def-fun
(macro args `(define-function ,@args)))

(define len length)
(define (car lst)
(head lst))

(define (cdr lst)
(tail lst))

(define label
(macro args `(define ,@args)))
Expand Down
81 changes: 48 additions & 33 deletions dsk/lib/lisp/core.lsp
Original file line number Diff line number Diff line change
Expand Up @@ -44,62 +44,47 @@
(define-macro (let params values body)
`((function ,params ,body) ,@values))

(define (caar x)
(car (car x)))

(define (cadr x)
(car (cdr x)))

(define (cdar x)
(cdr (car x)))

(define (cddr x)
(cdr (cdr x)))

(define (rest x)
(cdr x))

(define (first x)
(car x))

(define (second x)
(first (rest x)))

(define (third x)
(second (rest x)))

(define (reduce f ls)
(if (nil? (rest ls)) (first ls)
(f (first ls) (reduce f (rest ls)))))
(if (nil? (tail ls)) (head ls)
(f (head ls) (reduce f (tail ls)))))

(define (map f ls)
(if (nil? ls) nil
(cons
(f (first ls))
(map f (rest ls)))))
(f (head ls))
(map f (tail ls)))))

(define (filter f ls)
(if (nil? ls) nil
(if (f (first ls))
(cons (first ls) (filter f (rest ls)))
(filter f (rest ls)))))
(if (f (head ls))
(cons (head ls) (filter f (tail ls)))
(filter f (tail ls)))))

(define (intersection a b)
(filter (function (x) (contains? b x)) a))

(define (reverse x)
(if (nil? x) x
(append (reverse (rest x)) (cons (first x) '()))))
(append (reverse (tail x)) (cons (head x) '()))))

(define (range i n)
(if (= i n) nil
(append (list i) (range (+ i 1) n))))

(define (min lst)
(head (sort lst)))

(define (max lst)
(head (reverse (sort lst))))

(define (abs x)
(if (> x 0) x (- x)))

(define (string-join ls s)
(reduce (function (x y) (string x s y)) ls))

(define (read-line)
(bytes->string (reverse (rest (reverse (read-file-bytes "/dev/console" 256))))))
(bytes->string (reverse (tail (reverse (read-file-bytes "/dev/console" 256))))))

(define (read-char)
(bytes->string (read-file-bytes "/dev/console" 4)))
Expand Down Expand Up @@ -135,3 +120,33 @@

(define (chars contents)
(split contents ""))

(define (first lst)
(nth lst 0))

(define (second lst)
(nth lst 1))

(define (third lst)
(nth lst 2))

(define (last lst)
(nth lst
(if (= (length lst) 0) 0 (- (length lst) 1))))

(define (caar x)
(car (car x)))

(define (cadr x)
(car (cdr x)))

(define (cdar x)
(cdr (car x)))

(define (cddr x)
(cdr (cdr x)))

(define rest cdr)
(define len length)
(define rev reverse)
(define uniq unique)
2 changes: 1 addition & 1 deletion dsk/tmp/lisp/factorial.lsp
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@

(println
(if (nil? args) "Usage: factorial <num>"
(factorial (string->number (car args)))))
(factorial (string->number (head args)))))
2 changes: 1 addition & 1 deletion dsk/tmp/lisp/fibonacci.lsp
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@

(println
(if (nil? args) "Usage: fibonacci <num>"
(fibonacci (string->number (car args)))))
(fibonacci (string->number (head args)))))
3 changes: 0 additions & 3 deletions dsk/tmp/lisp/geotime.lsp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
(/ (* 2 pi) 365.0)
(+ (days timestamp) (/ (- (hours timestamp) 12.0) 24.0))))))

(define (abs x)
(if (< x 0) (- x) x))

(define (pad x)
(string (if (< x 10) "0" "") x))

Expand Down
2 changes: 1 addition & 1 deletion dsk/tmp/lisp/pi.lsp
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@

(println
(if (nil? args) "Usage: pi <precision>"
(pi-digits (string->number (car args)))))
(pi-digits (string->number (head args)))))
2 changes: 1 addition & 1 deletion dsk/tmp/lisp/sum.lsp
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

(println
(if (nil? args) "Usage: sum <num>"
(sum (string->number (car args)) 0)))
(sum (string->number (head args)) 0)))
3 changes: 2 additions & 1 deletion src/usr/lisp/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ pub fn default_env() -> Rc<RefCell<Env>> {
data.insert("number-type".to_string(), Exp::Primitive(primitive::lisp_number_type));
data.insert("parse".to_string(), Exp::Primitive(primitive::lisp_parse));
data.insert("list".to_string(), Exp::Primitive(primitive::lisp_list));
data.insert("uniq".to_string(), Exp::Primitive(primitive::lisp_uniq));
data.insert("sort".to_string(), Exp::Primitive(primitive::lisp_sort));
data.insert("unique".to_string(), Exp::Primitive(primitive::lisp_unique));
data.insert("nth".to_string(), Exp::Primitive(primitive::lisp_nth));
data.insert("contains?".to_string(), Exp::Primitive(primitive::lisp_contains));
data.insert("slice".to_string(), Exp::Primitive(primitive::lisp_slice));
data.insert("chunks".to_string(), Exp::Primitive(primitive::lisp_chunks));
Expand Down
10 changes: 5 additions & 5 deletions src/usr/lisp/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn eval_eq_args(args: &[Exp], env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
Ok(Exp::Bool(a == b))
}

fn eval_car_args(args: &[Exp], env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
fn eval_head_args(args: &[Exp], env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
ensure_length_eq!(args, 1);
match eval(&args[0], env)? {
Exp::List(list) => {
Expand All @@ -46,7 +46,7 @@ fn eval_car_args(args: &[Exp], env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
}
}

fn eval_cdr_args(args: &[Exp], env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
fn eval_tail_args(args: &[Exp], env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
ensure_length_eq!(args, 1);
match eval(&args[0], env)? {
Exp::List(list) => {
Expand Down Expand Up @@ -149,7 +149,7 @@ pub fn eval_args(args: &[Exp], env: &mut Rc<RefCell<Env>>) -> Result<Vec<Exp>, E

pub const BUILT_INS: [&str; 32] = [
"quote", "quasiquote", "unquote", "unquote-splicing",
"atom", "eq", "car", "cdr", "cons",
"atom", "eq", "head", "tail", "cons",
"if", "cond", "while",
"set",
"define", "def", "label",
Expand Down Expand Up @@ -180,8 +180,8 @@ pub fn eval(exp: &Exp, env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
Exp::Sym(s) if s == "quote" => return eval_quote_args(args),
Exp::Sym(s) if s == "atom" => return eval_atom_args(args, env),
Exp::Sym(s) if s == "eq" => return eval_eq_args(args, env),
Exp::Sym(s) if s == "car" => return eval_car_args(args, env),
Exp::Sym(s) if s == "cdr" => return eval_cdr_args(args, env),
Exp::Sym(s) if s == "head" => return eval_head_args(args, env),
Exp::Sym(s) if s == "tail" => return eval_tail_args(args, env),
Exp::Sym(s) if s == "cons" => return eval_cons_args(args, env),
Exp::Sym(s) if s == "set" => return eval_set_args(args, env),
Exp::Sym(s) if s == "while" => return eval_while_args(args, env),
Expand Down
13 changes: 7 additions & 6 deletions src/usr/lisp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,13 @@ fn test_lisp() {
assert_eq!(eval!("(eq 1 1.0)"), "false");
assert_eq!(eval!("(eq 1.0 1.0)"), "true");

// car
assert_eq!(eval!("(car (quote (1)))"), "1");
assert_eq!(eval!("(car (quote (1 2 3)))"), "1");
// head
assert_eq!(eval!("(head (quote (1)))"), "1");
assert_eq!(eval!("(head (quote (1 2 3)))"), "1");

// cdr
assert_eq!(eval!("(cdr (quote (1)))"), "()");
assert_eq!(eval!("(cdr (quote (1 2 3)))"), "(2 3)");
// tail
assert_eq!(eval!("(tail (quote (1)))"), "()");
assert_eq!(eval!("(tail (quote (1 2 3)))"), "(2 3)");

// cons
assert_eq!(eval!("(cons (quote 1) (quote (2 3)))"), "(1 2 3)");
Expand Down Expand Up @@ -484,6 +484,7 @@ fn test_lisp() {
eval!("(define x 'a)");
assert_eq!(eval!("`(x ,x y)"), "(x a y)");
assert_eq!(eval!("`(x ,x y ,(+ 1 2))"), "(x a y 3)");
assert_eq!(eval!("`(list ,(+ 1 2) 4)"), "(list 3 4)");

// unquote-splice
eval!("(define x '(1 2 3))");
Expand Down
44 changes: 33 additions & 11 deletions src/usr/lisp/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ pub fn lisp_add(args: &[Exp]) -> Result<Exp, Err> {
pub fn lisp_sub(args: &[Exp]) -> Result<Exp, Err> {
ensure_length_gt!(args, 0);
let args = list_of_numbers(args)?;
let car = args[0].clone();
let head = args[0].clone();
if args.len() == 1 {
Ok(Exp::Num(-car))
Ok(Exp::Num(-head))
} else {
let res = args[1..].iter().fold(Number::Int(0), |acc, a| acc + a.clone());
Ok(Exp::Num(car - res))
Ok(Exp::Num(head - res))
}
}

Expand All @@ -71,8 +71,8 @@ pub fn lisp_div(args: &[Exp]) -> Result<Exp, Err> {
return Err(Err::Reason("Division by zero".to_string()));
}
}
let car = args[0].clone();
let res = args[1..].iter().fold(car, |acc, a| acc / a.clone());
let head = args[0].clone();
let res = args[1..].iter().fold(head, |acc, a| acc / a.clone());
Ok(Exp::Num(res))
}

Expand All @@ -84,16 +84,16 @@ pub fn lisp_mod(args: &[Exp]) -> Result<Exp, Err> {
return Err(Err::Reason("Division by zero".to_string()));
}
}
let car = args[0].clone();
let res = args[1..].iter().fold(car, |acc, a| acc % a.clone());
let head = args[0].clone();
let res = args[1..].iter().fold(head, |acc, a| acc % a.clone());
Ok(Exp::Num(res))
}

pub fn lisp_exp(args: &[Exp]) -> Result<Exp, Err> {
ensure_length_gt!(args, 0);
let args = list_of_numbers(args)?;
let car = args[0].clone();
let res = args[1..].iter().fold(car, |acc, a| acc.pow(a));
let head = args[0].clone();
let res = args[1..].iter().fold(head, |acc, a| acc.pow(a));
Ok(Exp::Num(res))
}

Expand Down Expand Up @@ -311,7 +311,7 @@ pub fn lisp_list(args: &[Exp]) -> Result<Exp, Err> {
Ok(Exp::List(args.to_vec()))
}

pub fn lisp_uniq(args: &[Exp]) -> Result<Exp, Err> {
pub fn lisp_unique(args: &[Exp]) -> Result<Exp, Err> {
ensure_length_eq!(args, 1);
if let Exp::List(list) = &args[0] {
let mut list = list.clone();
Expand Down Expand Up @@ -342,6 +342,28 @@ pub fn lisp_contains(args: &[Exp]) -> Result<Exp, Err> {
}
}

pub fn lisp_nth(args: &[Exp]) -> Result<Exp, Err> {
ensure_length_eq!(args, 2);
let i = usize::try_from(number(&args[1])?)?;
match &args[0] {
Exp::List(l) => {
if let Some(e) = l.iter().nth(i) {
Ok(e.clone())
} else {
Ok(Exp::List(Vec::new()))
}
}
Exp::Str(s) => {
if let Some(c) = s.chars().nth(i) {
Ok(Exp::Str(c.to_string()))
} else {
Ok(Exp::Str("".to_string()))
}
}
_ => Err(Err::Reason("Expected first arg to be a list or a string".to_string()))
}
}

pub fn lisp_slice(args: &[Exp]) -> Result<Exp, Err> {
let (a, b) = match args.len() {
2 => (usize::try_from(number(&args[1])?)?, 1),
Expand All @@ -357,7 +379,7 @@ pub fn lisp_slice(args: &[Exp]) -> Result<Exp, Err> {
let s: String = s.chars().skip(a).take(b).collect();
Ok(Exp::Str(s))
}
_ => Err(Err::Reason("Expected first arg to be a list or a number".to_string()))
_ => Err(Err::Reason("Expected first arg to be a list or a string".to_string()))
}
}

Expand Down