|
use crate::ast::Expr; |
|
|
|
pub fn add(args: Vec<Expr>) -> Result<Expr, String> { |
|
let mut sum = 0.0; |
|
for arg in args { |
|
match arg { |
|
Expr::Number(n) => sum += n, |
|
_ => return Err("Arguments to + must be numbers".to_string()), |
|
} |
|
} |
|
Ok(Expr::Number(sum)) |
|
} |
|
|
|
pub fn subtract(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.is_empty() { |
|
return Err("- requires at least one argument".to_string()); |
|
} |
|
|
|
let mut result = match &args[0] { |
|
Expr::Number(n) => *n, |
|
_ => return Err("Arguments to - must be numbers".to_string()), |
|
}; |
|
|
|
if args.len() == 1 { |
|
return Ok(Expr::Number(-result)); |
|
} |
|
|
|
for arg in &args[1..] { |
|
match arg { |
|
Expr::Number(n) => result -= n, |
|
_ => return Err("Arguments to - must be numbers".to_string()), |
|
} |
|
} |
|
Ok(Expr::Number(result)) |
|
} |
|
|
|
pub fn multiply(args: Vec<Expr>) -> Result<Expr, String> { |
|
let mut product = 1.0; |
|
for arg in args { |
|
match arg { |
|
Expr::Number(n) => product *= n, |
|
_ => return Err("Arguments to * must be numbers".to_string()), |
|
} |
|
} |
|
Ok(Expr::Number(product)) |
|
} |
|
|
|
pub fn divide(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.is_empty() { |
|
return Err("/ requires at least one argument".to_string()); |
|
} |
|
|
|
let mut result = match &args[0] { |
|
Expr::Number(n) => *n, |
|
_ => return Err("Arguments to / must be numbers".to_string()), |
|
}; |
|
|
|
if args.len() == 1 { |
|
if result == 0.0 { |
|
return Err("Division by zero".to_string()); |
|
} |
|
return Ok(Expr::Number(1.0 / result)); |
|
} |
|
|
|
for arg in &args[1..] { |
|
match arg { |
|
Expr::Number(n) => { |
|
if *n == 0.0 { |
|
return Err("Division by zero".to_string()); |
|
} |
|
result /= n; |
|
}, |
|
_ => return Err("Arguments to / must be numbers".to_string()), |
|
} |
|
} |
|
Ok(Expr::Number(result)) |
|
} |
|
|
|
pub fn equal(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() < 2 { |
|
return Err("= requires at least two arguments".to_string()); |
|
} |
|
|
|
let first = &args[0]; |
|
for arg in &args[1..] { |
|
if first != arg { |
|
return Ok(Expr::Boolean(false)); |
|
} |
|
} |
|
Ok(Expr::Boolean(true)) |
|
} |
|
|
|
pub fn less_than(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() < 2 { |
|
return Err("< requires at least two arguments".to_string()); |
|
} |
|
|
|
for i in 0..args.len() - 1 { |
|
let (left, right) = (&args[i], &args[i + 1]); |
|
match (left, right) { |
|
(Expr::Number(a), Expr::Number(b)) => { |
|
if a >= b { |
|
return Ok(Expr::Boolean(false)); |
|
} |
|
} |
|
_ => return Err("Arguments to < must be numbers".to_string()), |
|
} |
|
} |
|
Ok(Expr::Boolean(true)) |
|
} |
|
|
|
pub fn greater_than(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() < 2 { |
|
return Err("> requires at least two arguments".to_string()); |
|
} |
|
|
|
for i in 0..args.len() - 1 { |
|
let (left, right) = (&args[i], &args[i + 1]); |
|
match (left, right) { |
|
(Expr::Number(a), Expr::Number(b)) => { |
|
if a <= b { |
|
return Ok(Expr::Boolean(false)); |
|
} |
|
} |
|
_ => return Err("Arguments to > must be numbers".to_string()), |
|
} |
|
} |
|
Ok(Expr::Boolean(true)) |
|
} |
|
|
|
pub fn cons(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() != 2 { |
|
return Err("cons requires exactly two arguments".to_string()); |
|
} |
|
|
|
let car = args[0].clone(); |
|
let cdr = args[1].clone(); |
|
|
|
match cdr { |
|
Expr::List(mut list) => { |
|
list.insert(0, car); |
|
Ok(Expr::List(list)) |
|
} |
|
Expr::Nil => Ok(Expr::List(vec![car])), |
|
_ => Err("Second argument to cons must be a list or nil".to_string()), |
|
} |
|
} |
|
|
|
pub fn car(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() != 1 { |
|
return Err("car requires exactly one argument".to_string()); |
|
} |
|
|
|
match &args[0] { |
|
Expr::List(list) => { |
|
if list.is_empty() { |
|
Err("Cannot take car of empty list".to_string()) |
|
} else { |
|
Ok(list[0].clone()) |
|
} |
|
} |
|
_ => Err("Argument to car must be a list".to_string()), |
|
} |
|
} |
|
|
|
pub fn cdr(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() != 1 { |
|
return Err("cdr requires exactly one argument".to_string()); |
|
} |
|
|
|
match &args[0] { |
|
Expr::List(list) => { |
|
if list.is_empty() { |
|
Err("Cannot take cdr of empty list".to_string()) |
|
} else { |
|
Ok(Expr::List(list[1..].to_vec())) |
|
} |
|
} |
|
_ => Err("Argument to cdr must be a list".to_string()), |
|
} |
|
} |
|
|
|
pub fn is_null(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() != 1 { |
|
return Err("null? requires exactly one argument".to_string()); |
|
} |
|
|
|
Ok(Expr::Boolean(matches!(args[0], Expr::Nil))) |
|
} |
|
|
|
pub fn is_number(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() != 1 { |
|
return Err("number? requires exactly one argument".to_string()); |
|
} |
|
|
|
Ok(Expr::Boolean(matches!(args[0], Expr::Number(_)))) |
|
} |
|
|
|
pub fn is_symbol(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() != 1 { |
|
return Err("symbol? requires exactly one argument".to_string()); |
|
} |
|
|
|
Ok(Expr::Boolean(matches!(args[0], Expr::Symbol(_)))) |
|
} |
|
|
|
pub fn is_boolean(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() != 1 { |
|
return Err("boolean? requires exactly one argument".to_string()); |
|
} |
|
|
|
Ok(Expr::Boolean(matches!(args[0], Expr::Boolean(_)))) |
|
} |
|
|
|
pub fn is_list(args: Vec<Expr>) -> Result<Expr, String> { |
|
if args.len() != 1 { |
|
return Err("list? requires exactly one argument".to_string()); |
|
} |
|
|
|
Ok(Expr::Boolean(matches!(args[0], Expr::List(_)))) |
|
} |
|
|
|
pub fn display_help() -> Result<Expr, String> { |
|
let help_text = r#" |
|
Lisp Interpreter Help |
|
===================== |
|
|
|
This is a simple Scheme-like interpreter with the following features: |
|
|
|
Basic Data Types: |
|
- Numbers: 1, 3.14, -5 |
|
- Booleans: true, false |
|
- Strings: "hello" |
|
- Symbols: x, hello-world |
|
- Lists: (1 2 3), (a b c) |
|
|
|
Arithmetic Operations: |
|
- (+ a b c ...) - Addition |
|
- (- a b c ...) - Subtraction |
|
- (* a b c ...) - Multiplication |
|
- (/ a b c ...) - Division |
|
|
|
Comparison Operations: |
|
- (= a b c ...) - Equality |
|
- (< a b c ...) - Less than |
|
- (> a b c ...) - Greater than |
|
|
|
List Operations: |
|
- (cons a b) - Construct a list |
|
- (car lst) - Get first element |
|
- (cdr lst) - Get rest of elements |
|
- (null? x) - Check if null |
|
- (list a b c ...) - Create a list |
|
|
|
Type Predicates: |
|
- (number? x) - Check if number |
|
- (symbol? x) - Check if symbol |
|
- (boolean? x) - Check if boolean |
|
- (list? x) - Check if list |
|
|
|
Control Structures: |
|
- (if condition then-expr else-expr) - Conditional |
|
- (define symbol value) - Define variable |
|
- (lambda (params) body) - Create function |
|
- (begin expr1 expr2 ...) - Execute expressions in sequence |
|
|
|
Quoting: |
|
- 'expr - Quote an expression (equivalent to (quote expr)) |
|
- Quoting prevents evaluation of expressions |
|
|
|
Special Commands: |
|
- (help) - Show this help |
|
- Ctrl+D - Exit interpreter |
|
|
|
Examples: |
|
- (+ 1 2 3) => 6 |
|
- (define x 10) => x |
|
- (if (> x 5) "big" "small") => "big" |
|
- ((lambda (x) (* x 2)) 5) => 10 |
|
- 'hello => hello |
|
- '(1 2 3) => (1 2 3) |
|
"#; |
|
|
|
println!("{}", help_text); |
|
Ok(Expr::Nil) |
|
} |