diff --git a/src/usr/lisp.rs b/src/usr/lisp.rs
index 40ad982..0685e25 100644
@@ -1,4 +1,5 @@
-use crate::{api, usr};
+use crate::{api, usr, debug, syscall};
+use crate::api::fs;
use crate::api::console::Style;
use crate::api::prompt::Prompt;
use alloc::string::ToString;
@@ -89,7 +90,7 @@ struct Env<'a> {
// Parser
fn is_symbol_letter(c: char) -> bool {
- let chars = "<>=-+*/";
+ let chars = "<>=-+*?:/";
c.is_alphanumeric() || chars.contains(c)
}
@@ -162,75 +163,89 @@ macro_rules! ensure_tonicity {
fn default_env<'a>() -> Env<'a> {
let mut data: BTreeMap<String, Exp> = BTreeMap::new();
- data.insert(
- "*".to_string(),
- Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
- let res = list_of_floats(args)?.iter().fold(1.0, |res, a| res * a);
- Ok(Exp::Num(res))
- })
- );
- data.insert(
- "+".to_string(),
- Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
- let res = list_of_floats(args)?.iter().fold(0.0, |res, a| res + a);
- Ok(Exp::Num(res))
- })
- );
- data.insert(
- "-".to_string(),
- Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
- let floats = list_of_floats(args)?;
- let first = *floats.first().ok_or(Err::Reason("Expected at least one number".to_string()))?;
- let sum_of_rest = floats[1..].iter().fold(0.0, |sum, a| sum + a);
- Ok(Exp::Num(first - sum_of_rest))
- })
- );
- data.insert(
- "=".to_string(),
- Exp::Func(ensure_tonicity!(|a, b| approx_eq!(f64, a, b)))
- );
- data.insert(
- ">".to_string(),
- Exp::Func(ensure_tonicity!(|a, b| !approx_eq!(f64, a, b) && a > b))
- );
- data.insert(
- ">=".to_string(),
- Exp::Func(ensure_tonicity!(|a, b| approx_eq!(f64, a, b) || a > b))
- );
- data.insert(
- "<".to_string(),
- Exp::Func(ensure_tonicity!(|a, b| !approx_eq!(f64, a, b) && a < b))
- );
- data.insert(
- "<=".to_string(),
- Exp::Func(ensure_tonicity!(|a, b| approx_eq!(f64, a, b) || a < b))
- );
+
+ data.insert("=".to_string(), Exp::Func(ensure_tonicity!(|a, b| approx_eq!(f64, a, b))));
+ data.insert(">".to_string(), Exp::Func(ensure_tonicity!(|a, b| !approx_eq!(f64, a, b) && a > b)));
+ data.insert(">=".to_string(), Exp::Func(ensure_tonicity!(|a, b| approx_eq!(f64, a, b) || a > b)));
+ data.insert("<".to_string(), Exp::Func(ensure_tonicity!(|a, b| !approx_eq!(f64, a, b) && a < b)));
+ data.insert("<=".to_string(), Exp::Func(ensure_tonicity!(|a, b| approx_eq!(f64, a, b) || a < b)));
+
+ data.insert("*".to_string(), Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
+ let res = list_of_floats(args)?.iter().fold(1.0, |res, a| res * a);
+ Ok(Exp::Num(res))
+ }));
+ data.insert("+".to_string(), Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
+ let res = list_of_floats(args)?.iter().fold(0.0, |res, a| res + a);
+ Ok(Exp::Num(res))
+ }));
+ data.insert("-".to_string(), Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
+ let floats = list_of_floats(args)?;
+ let first = *floats.first().ok_or(Err::Reason("Expected at least one number".to_string()))?;
+ let sum_of_rest = floats[1..].iter().fold(0.0, |sum, a| sum + a);
+ Ok(Exp::Num(first - sum_of_rest))
+ }));
+
+ data.insert("decode-float".to_string(), Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
+ let floats = list_of_floats(args)?;
+ let n = *floats.first().ok_or(Err::Reason("Expected one number".to_string()))?;
+ Ok(Exp::Num(n.to_bits() as f64))
+ }));
+ data.insert("encode-float".to_string(), Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
+ let floats = list_of_floats(args)?;
+ let n = *floats.first().ok_or(Err::Reason("Expected one number".to_string()))?;
+ Ok(Exp::Num(f64::from_bits(n as u64)))
+ }));
+
+ data.insert("read-file".to_string(), Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
+ let arg = first(args)?;
+ let path = string(&arg)?;
+ let contents = fs::read_to_string(&path).or(Err(Err::Reason("Could not read file".to_string())))?;
+ Ok(Exp::Str(contents))
+ }));
+
+ data.insert("lines".to_string(), Exp::Func(|args: &[Exp]| -> Result<Exp, Err> {
+ let arg = first(args)?;
+ let s = string(&arg)?;
+ let lines = s.lines().map(|line| Exp::Str(line.to_string())).collect();
+ Ok(Exp::List(lines))
+ }));
Env { data, outer: None }
}
+fn first(exps: &[Exp]) -> Result<Exp, Err> {
+ match exps.first() {
+ Some(exp) => Ok(exp.clone()),
+ None => Err(Err::Reason("Expected an expression".to_string()))
+ }
+}
+
fn list_of_floats(args: &[Exp]) -> Result<Vec<f64>, Err> {
- args.iter().map(|x| single_float(x)).collect()
+ args.iter().map(|x| float(x)).collect()
}
-fn single_float(exp: &Exp) -> Result<f64, Err> {
+fn float(exp: &Exp) -> Result<f64, Err> {
match exp {
Exp::Num(num) => Ok(*num),
_ => Err(Err::Reason("Expected a number".to_string())),
}
}
+fn string(exp: &Exp) -> Result<String, Err> {
+ match exp {
+ Exp::Str(s) => Ok(s.to_string()),
+ _ => Err(Err::Reason("Expected a string".to_string())),
+ }
+}
+
// Eval
-fn eval_quote_args(arg_forms: &[Exp]) -> Result<Exp, Err> {
- let first_form = arg_forms.first().ok_or(Err::Reason("Expected first form".to_string()))?;
- Ok(first_form.clone())
+fn eval_quote_args(args: &[Exp]) -> Result<Exp, Err> {
+ first(args)
}
-fn eval_atom_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
- let first_form = arg_forms.first().ok_or(Err::Reason("Expected first form".to_string()))?;
- let first_eval = eval(first_form, env)?;
- match first_eval {
+fn eval_atom_args(args: &[Exp], env: &mut Env) -> Result<Exp, Err> {
+ match eval(&first(args)?, env)? {
Exp::Sym(_) => Ok(Exp::Bool(true)),
_ => Ok(Exp::Bool(false)),
}
@@ -258,10 +273,8 @@ fn eval_eq_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
}
}
-fn eval_car_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
- let first_form = arg_forms.first().ok_or(Err::Reason("Expected first form".to_string()))?;
- let first_eval = eval(first_form, env)?;
- match first_eval {
+fn eval_car_args(args: &[Exp], env: &mut Env) -> Result<Exp, Err> {
+ match eval(&first(args)?, env)? {
Exp::List(list) => {
let exp = list.first().ok_or(Err::Reason("List cannot be empty".to_string()))?; // TODO: return nil?
Ok(exp.clone())
@@ -270,10 +283,8 @@ fn eval_car_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
}
}
-fn eval_cdr_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
- let first_form = arg_forms.first().ok_or(Err::Reason("Expected first form".to_string()))?;
- let first_eval = eval(first_form, env)?;
- match first_eval {
+fn eval_cdr_args(args: &[Exp], env: &mut Env) -> Result<Exp, Err> {
+ match eval(&first(args)?, env)? {
Exp::List(list) => {
if list.is_empty() {
return Err(Err::Reason("List cannot be empty".to_string())) // TODO: return nil?
@@ -311,11 +322,7 @@ fn eval_cond_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
let pred = eval(&list[0], env)?;
let exp = eval(&list[1], env)?;
match pred {
- Exp::Bool(b) => {
- if b {
- return Ok(exp);
- }
- },
+ Exp::Bool(b) if b => return Ok(exp),
_ => continue,
}
},
@@ -361,12 +368,11 @@ fn eval_defun_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
eval_label_args(&label_args, env)
}
-fn eval_print_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
- let first_form = arg_forms.first().ok_or(Err::Reason("Expected first form".to_string()))?;
- if arg_forms.len() > 1 {
+fn eval_print_args(args: &[Exp], env: &mut Env) -> Result<Exp, Err> {
+ if args.len() > 1 {
return Err(Err::Reason("Print can only have one form".to_string()))
}
- match eval(first_form, env) {
+ match eval(&first(args)?, env) {
Ok(Exp::Str(s)) => {
println!("{}", s);
Ok(Exp::Str(s))
@@ -381,6 +387,31 @@ fn eval_print_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
}
}
+fn eval_syscall_args(arg_forms: &[Exp], env: &mut Env) -> Result<Exp, Err> {
+ let first_form = arg_forms.first().ok_or(Err::Reason("Expected syscall number".to_string()))?;
+ let first_eval = eval(first_form, env)?;
+ let number = match first_eval {
+ Exp::Num(n) => n,
+ _ => return Err(Err::Reason("Expected syscall number".to_string())),
+ };
+ let args: Result<Vec<u64>, Err> = arg_forms.iter().map(|arg_form| {
+ match eval(arg_form, env) {
+ Ok(Exp::Str(s)) => Ok(s.as_ptr() as u64),
+ Ok(Exp::Num(i)) => Ok(i as u64),
+ _ => Err(Err::Reason("Invalid syscall argument".to_string())),
+ }
+ }).collect();
+ let args = &args?[1..];
+ let res = match args.len() {
+ 0 => unsafe { syscall!(number) },
+ 1 => unsafe { syscall!(number, args[0]) },
+ 2 => unsafe { syscall!(number, args[0], args[1]) },
+ 3 => unsafe { syscall!(number, args[0], args[1], args[2]) },
+ _ => return Err(Err::Reason("Invalid number of syscall arguments".to_string())),
+ };
+ Ok(Exp::Num(res as f64))
+}
+
fn eval_built_in_form(exp: &Exp, arg_forms: &[Exp], env: &mut Env) -> Option<Result<Exp, Err>> {
match exp {
Exp::Sym(s) => {
@@ -400,6 +431,7 @@ fn eval_built_in_form(exp: &Exp, arg_forms: &[Exp], env: &mut Env) -> Option<Res
"defun" | "defn" => Some(eval_defun_args(arg_forms, env)),
"print" => Some(eval_print_args(arg_forms, env)),
+ "syscall" => Some(eval_syscall_args(arg_forms, env)),
_ => None,
}
},
@@ -419,7 +451,7 @@ fn env_get(k: &str, env: &Env) -> Option<Exp> {
}
}
-fn list_of_symbol_strings(form: Rc<Exp>) -> Result<Vec<String>, Err> {
+fn list_of_symbols(form: Rc<Exp>) -> Result<Vec<String>, Err> {
let list = match form.as_ref() {
Exp::List(s) => Ok(s.clone()),
_ => Err(Err::Reason("Expected args form to be a list".to_string()))
@@ -433,7 +465,7 @@ fn list_of_symbol_strings(form: Rc<Exp>) -> Result<Vec<String>, Err> {
}
fn env_for_lambda<'a>(params: Rc<Exp>, arg_forms: &[Exp], outer_env: &'a mut Env) -> Result<Env<'a>, Err> {
- let ks = list_of_symbol_strings(params)?;
+ let ks = list_of_symbols(params)?;
if ks.len() != arg_forms.len() {
return Err(Err::Reason(format!("Expected {} arguments, got {}", ks.len(), arg_forms.len())));
}
@@ -454,7 +486,7 @@ fn eval_forms(arg_forms: &[Exp], env: &mut Env) -> Result<Vec<Exp>, Err> {
fn eval(exp: &Exp, env: &mut Env) -> Result<Exp, Err> {
match exp {
- Exp::Sym(k) => env_get(k, env).ok_or(Err::Reason(format!("Unexpected symbol k='{}'", k))),
+ Exp::Sym(k) => env_get(k, env).ok_or(Err::Reason(format!("Unexpected symbol '{}'", k))),
Exp::Bool(_) => Ok(exp.clone()),
Exp::Num(_) => Ok(exp.clone()),
Exp::Str(_) => Ok(exp.clone()),
@@ -536,6 +568,10 @@ fn repl(env: &mut Env) -> usr::shell::ExitCode {
println!();
continue;
}
+ match parse_exp(&line) {
+ Ok((_, exp)) => debug!("{}", exp),
+ Err(e) => debug!("{:?}", e),
+ }
match parse_eval(&line, env) {
Ok(res) => {
println!("{}\n", res);
@@ -676,4 +712,7 @@ fn test_lisp() {
assert_eq!(eval!("(= 6 4)"), "false");
assert_eq!(eval!("(= 6 6)"), "true");
assert_eq!(eval!("(= (+ 0.15 0.15) (+ 0.1 0.2))"), "true");
+
+ // string
+ assert_eq!(eval!("(eq \"Hello, World!\" \"foo\")"), "false");
}