small but full lisp
This commit is contained in:
parent
50329f1d9f
commit
53ed6426c6
0
assets/start.lisp
Normal file
0
assets/start.lisp
Normal file
106
src/environ.rs
106
src/environ.rs
|
@ -1,38 +1,78 @@
|
||||||
use crate::Expr;
|
|
||||||
use crate::RispError;
|
|
||||||
use crate::HashMap;
|
|
||||||
use crate::parse_list_of_floats;
|
use crate::parse_list_of_floats;
|
||||||
|
use crate::Expr;
|
||||||
|
use crate::HashMap;
|
||||||
|
use crate::RispError;
|
||||||
|
|
||||||
pub
|
macro_rules! ensure_tonicity {
|
||||||
struct Environ {
|
($check_fn:expr) => {{
|
||||||
pub data: HashMap<String, Expr>,
|
|args: &[Expr]| -> Result<Expr, RispError> {
|
||||||
|
let floats = parse_list_of_floats(args)?;
|
||||||
|
let first = floats.first().ok_or(RispError::Reason(
|
||||||
|
"expected at least one number".to_string(),
|
||||||
|
))?;
|
||||||
|
let rest = &floats[1..];
|
||||||
|
fn f(prev: &f64, xs: &[f64]) -> bool {
|
||||||
|
match xs.first() {
|
||||||
|
Some(x) => $check_fn(prev, x) && f(x, &xs[1..]),
|
||||||
|
None => true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(Expr::Bool(f(first, rest)))
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
pub fn env_get(k: &str, env: &Environ) -> Option<Expr> {
|
||||||
|
match env.data.get(k) {
|
||||||
|
Some(exp) => Some(exp.clone()),
|
||||||
|
None => match &env.outer {
|
||||||
|
Some(outer_env) => env_get(k, &outer_env),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub fn default_env() -> Environ {
|
pub struct Environ<'a> {
|
||||||
let mut data: HashMap<String, Expr> = HashMap::new();
|
pub data: HashMap<String, Expr>,
|
||||||
data.insert(
|
pub outer: Option<&'a Environ<'a>>,
|
||||||
"+".to_string(),
|
}
|
||||||
Expr::Func(
|
|
||||||
|args: &[Expr]| -> Result<Expr, RispError> {
|
pub fn default_env<'a>() -> Environ<'a> {
|
||||||
let sum = parse_list_of_floats(args)?.iter().fold(0.0, |sum, a| sum + a);
|
let mut data: HashMap<String, Expr> = HashMap::new();
|
||||||
|
data.insert(
|
||||||
Ok(Expr::Number(sum))
|
"+".to_string(),
|
||||||
}
|
Expr::Func(|args: &[Expr]| -> Result<Expr, RispError> {
|
||||||
)
|
let sum = parse_list_of_floats(args)?
|
||||||
);
|
.iter()
|
||||||
data.insert(
|
.fold(0.0, |sum, a| sum + a);
|
||||||
"-".to_string(),
|
|
||||||
Expr::Func(
|
Ok(Expr::Number(sum))
|
||||||
|args: &[Expr]| -> Result<Expr, RispError> {
|
}),
|
||||||
let floats = parse_list_of_floats(args)?;
|
);
|
||||||
let first = *floats.first().ok_or(RispError::Reason("expected at least one number".to_string()))?;
|
data.insert(
|
||||||
let sum_of_rest = floats[1..].iter().fold(0.0, |sum, a| sum + a);
|
"-".to_string(),
|
||||||
|
Expr::Func(|args: &[Expr]| -> Result<Expr, RispError> {
|
||||||
Ok(Expr::Number(first - sum_of_rest))
|
let floats = parse_list_of_floats(args)?;
|
||||||
}
|
let first = *floats.first().ok_or(RispError::Reason(
|
||||||
)
|
"expected at least one number".to_string(),
|
||||||
);
|
))?;
|
||||||
|
let sum_of_rest = floats[1..].iter().fold(0.0, |sum, a| sum + a);
|
||||||
Environ {data}
|
|
||||||
|
Ok(Expr::Number(first - sum_of_rest))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
data.insert("=".to_string(), Expr::Func(ensure_tonicity!(|a, b| a == b)));
|
||||||
|
data.insert(">".to_string(), Expr::Func(ensure_tonicity!(|a, b| a > b)));
|
||||||
|
data.insert(
|
||||||
|
">=".to_string(),
|
||||||
|
Expr::Func(ensure_tonicity!(|a, b| a >= b)),
|
||||||
|
);
|
||||||
|
data.insert("<".to_string(), Expr::Func(ensure_tonicity!(|a, b| a < b)));
|
||||||
|
data.insert(
|
||||||
|
"<=".to_string(),
|
||||||
|
Expr::Func(ensure_tonicity!(|a, b| a <= b)),
|
||||||
|
);
|
||||||
|
|
||||||
|
Environ { data, outer: None }
|
||||||
}
|
}
|
||||||
|
|
169
src/evaluate.rs
Normal file
169
src/evaluate.rs
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
use crate::environ::env_get;
|
||||||
|
use crate::Environ;
|
||||||
|
use crate::Expr;
|
||||||
|
use crate::HashMap;
|
||||||
|
use crate::RLambda;
|
||||||
|
use crate::Rc;
|
||||||
|
use crate::RispError;
|
||||||
|
|
||||||
|
pub fn eval(exp: &Expr, env: &mut Environ) -> Result<Expr, RispError> {
|
||||||
|
match exp {
|
||||||
|
Expr::Symbol(k) => {
|
||||||
|
env_get(k, env).ok_or(RispError::Reason(format!("unexpected symbol k='{}'", k)))
|
||||||
|
}
|
||||||
|
Expr::Bool(_a) => Ok(exp.clone()),
|
||||||
|
Expr::Number(_a) => Ok(exp.clone()),
|
||||||
|
|
||||||
|
Expr::List(list) => {
|
||||||
|
let first_form = list
|
||||||
|
.first()
|
||||||
|
.ok_or(RispError::Reason("expected a non-empty list".to_string()))?;
|
||||||
|
let arg_forms = &list[1..];
|
||||||
|
match eval_built_in_form(first_form, arg_forms, env) {
|
||||||
|
Some(res) => res,
|
||||||
|
None => {
|
||||||
|
let first_eval = eval(first_form, env)?;
|
||||||
|
match first_eval {
|
||||||
|
Expr::Func(f) => f(&eval_forms(arg_forms, env)?),
|
||||||
|
Expr::Lambda(lambda) => {
|
||||||
|
let new_env = &mut env_for_lambda(lambda.params_exp, arg_forms, env)?;
|
||||||
|
eval(&lambda.body_exp, new_env)
|
||||||
|
}
|
||||||
|
_ => Err(RispError::Reason(
|
||||||
|
"first form must be a function".to_string(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Func(_) => Err(RispError::Reason("unexpected form".to_string())),
|
||||||
|
Expr::Lambda(_) => Err(RispError::Reason("unexpected form".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_forms(arg_forms: &[Expr], env: &mut Environ) -> Result<Vec<Expr>, RispError> {
|
||||||
|
arg_forms.iter().map(|x| eval(x, env)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env_for_lambda<'a>(
|
||||||
|
params: Rc<Expr>,
|
||||||
|
arg_forms: &[Expr],
|
||||||
|
outer_env: &'a mut Environ,
|
||||||
|
) -> Result<Environ<'a>, RispError> {
|
||||||
|
let ks = parse_list_of_symbol_strings(params)?;
|
||||||
|
if ks.len() != arg_forms.len() {
|
||||||
|
return Err(RispError::Reason(format!(
|
||||||
|
"expected {} arguments, got {}",
|
||||||
|
ks.len(),
|
||||||
|
arg_forms.len()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let vs = eval_forms(arg_forms, outer_env)?;
|
||||||
|
let mut data: HashMap<String, Expr> = HashMap::new();
|
||||||
|
for (k, v) in ks.iter().zip(vs.iter()) {
|
||||||
|
data.insert(k.clone(), v.clone());
|
||||||
|
}
|
||||||
|
Ok(Environ {
|
||||||
|
data,
|
||||||
|
outer: Some(outer_env),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_list_of_symbol_strings(form: Rc<Expr>) -> Result<Vec<String>, RispError> {
|
||||||
|
let list = match form.as_ref() {
|
||||||
|
Expr::List(s) => Ok(s.clone()),
|
||||||
|
_ => Err(RispError::Reason(
|
||||||
|
"expected args form to be a list".to_string(),
|
||||||
|
)),
|
||||||
|
}?;
|
||||||
|
list.iter()
|
||||||
|
.map(|x| match x {
|
||||||
|
Expr::Symbol(s) => Ok(s.clone()),
|
||||||
|
_ => Err(RispError::Reason(
|
||||||
|
"expected symbols in the argument list".to_string(),
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_built_in_form(
|
||||||
|
exp: &Expr,
|
||||||
|
arg_forms: &[Expr],
|
||||||
|
env: &mut Environ,
|
||||||
|
) -> Option<Result<Expr, RispError>> {
|
||||||
|
match exp {
|
||||||
|
Expr::Symbol(s) => match s.as_ref() {
|
||||||
|
"if" => Some(eval_if_args(arg_forms, env)),
|
||||||
|
"def" => Some(eval_def_args(arg_forms, env)),
|
||||||
|
"fn" => Some(eval_lambda_args(arg_forms)),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_lambda_args(arg_forms: &[Expr]) -> Result<Expr, RispError> {
|
||||||
|
let params_exp = arg_forms
|
||||||
|
.first()
|
||||||
|
.ok_or(RispError::Reason("expected args form".to_string()))?;
|
||||||
|
let body_exp = arg_forms
|
||||||
|
.get(1)
|
||||||
|
.ok_or(RispError::Reason("expected second form".to_string()))?;
|
||||||
|
if arg_forms.len() > 2 {
|
||||||
|
return Err(RispError::Reason(
|
||||||
|
"fn definition can only have two forms ".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Expr::Lambda(RLambda {
|
||||||
|
body_exp: Rc::new(body_exp.clone()),
|
||||||
|
params_exp: Rc::new(params_exp.clone()),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_if_args(arg_forms: &[Expr], env: &mut Environ) -> Result<Expr, RispError> {
|
||||||
|
let test_form = arg_forms
|
||||||
|
.first()
|
||||||
|
.ok_or(RispError::Reason("expected test form".to_string()))?;
|
||||||
|
let test_eval = eval(test_form, env)?;
|
||||||
|
match test_eval {
|
||||||
|
Expr::Bool(b) => {
|
||||||
|
let form_idx = if b { 1 } else { 2 };
|
||||||
|
let res_form = arg_forms
|
||||||
|
.get(form_idx)
|
||||||
|
.ok_or(RispError::Reason(format!("expected form idx={}", form_idx)))?;
|
||||||
|
let res_eval = eval(res_form, env);
|
||||||
|
|
||||||
|
res_eval
|
||||||
|
}
|
||||||
|
_ => Err(RispError::Reason(format!(
|
||||||
|
"unexpected test form='{}'",
|
||||||
|
test_form.to_string()
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_def_args(arg_forms: &[Expr], env: &mut Environ) -> Result<Expr, RispError> {
|
||||||
|
let first_form = arg_forms
|
||||||
|
.first()
|
||||||
|
.ok_or(RispError::Reason("expected first form".to_string()))?;
|
||||||
|
let first_str = match first_form {
|
||||||
|
Expr::Symbol(s) => Ok(s.clone()),
|
||||||
|
_ => Err(RispError::Reason(
|
||||||
|
"expected first form to be a symbol".to_string(),
|
||||||
|
)),
|
||||||
|
}?;
|
||||||
|
let second_form = arg_forms
|
||||||
|
.get(1)
|
||||||
|
.ok_or(RispError::Reason("expected second form".to_string()))?;
|
||||||
|
if arg_forms.len() > 2 {
|
||||||
|
return Err(RispError::Reason(
|
||||||
|
"def can only have two forms ".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let second_eval = eval(second_form, env)?;
|
||||||
|
env.data.insert(first_str, second_eval);
|
||||||
|
|
||||||
|
Ok(first_form.clone())
|
||||||
|
}
|
152
src/main.rs
152
src/main.rs
|
@ -1,132 +1,98 @@
|
||||||
use std::io;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
use std::num::ParseFloatError;
|
use std::num::ParseFloatError;
|
||||||
use std::collections::HashMap;use std::io::Write;
|
use std::rc::Rc;
|
||||||
|
|
||||||
mod environ;
|
mod environ;
|
||||||
use environ::Environ;
|
|
||||||
use environ::default_env;
|
use environ::default_env;
|
||||||
|
use environ::Environ;
|
||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
use parser::parse;
|
use parser::parse;
|
||||||
use parser::parse_eval;
|
use parser::parse_eval;
|
||||||
use parser::parse_list_of_floats;
|
use parser::parse_list_of_floats;
|
||||||
|
|
||||||
|
mod evaluate;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum RispError{
|
enum RispError {
|
||||||
Reason(String),
|
Reason(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum Expr {
|
enum Expr {
|
||||||
|
Bool(bool),
|
||||||
Symbol(String),
|
Symbol(String),
|
||||||
Number(f64),
|
Number(f64),
|
||||||
List(Vec<Expr>),
|
List(Vec<Expr>),
|
||||||
Func(fn(&[Expr]) -> Result<Expr, RispError>), // bam
|
Func(fn(&[Expr]) -> Result<Expr, RispError>),
|
||||||
|
Lambda(RLambda),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct RLambda {
|
||||||
|
params_exp: Rc<Expr>,
|
||||||
|
body_exp: Rc<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Expr {
|
impl fmt::Display for Expr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let str = match self {
|
use Expr::*;
|
||||||
Expr::Symbol(s) => s.clone(),
|
let str = match self {
|
||||||
Expr::Number(n) => n.to_string(),
|
Bool(a) => a.to_string(),
|
||||||
Expr::List(list) => {
|
Symbol(s) => s.clone(),
|
||||||
let xs: Vec<String> = list
|
Number(n) => n.to_string(),
|
||||||
.iter()
|
List(list) => {
|
||||||
.map(|x| x.to_string())
|
let xs: Vec<String> = list.iter().map(|x| x.to_string()).collect();
|
||||||
.collect();
|
format!("({})", xs.join(","))
|
||||||
format!("({})", xs.join(","))
|
}
|
||||||
},
|
Func(_) => "Function {}".to_string(),
|
||||||
Expr::Func(_) => "Function {}".to_string(),
|
Lambda(_) => "Lambda {}".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "{}", str)
|
write!(f, "{}", str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn eval(exp: &Expr, env: &mut Environ) -> Result<Expr, RispError> {
|
|
||||||
match exp {
|
|
||||||
Expr::Symbol(k) =>
|
|
||||||
env.data.get(k)
|
|
||||||
.ok_or(
|
|
||||||
RispError::Reason(
|
|
||||||
format!("unexpected symbol k='{}'", k)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.map(|x| x.clone())
|
|
||||||
,
|
|
||||||
Expr::Number(_a) => Ok(exp.clone()),
|
|
||||||
Expr::List(list) => {
|
|
||||||
let first_form = list
|
|
||||||
.first()
|
|
||||||
.ok_or(RispError::Reason("expected a non-empty list".to_string()))?;
|
|
||||||
let arg_forms = &list[1..];
|
|
||||||
let first_eval = eval(first_form, env)?;
|
|
||||||
match first_eval {
|
|
||||||
Expr::Func(f) => {
|
|
||||||
let args_eval = arg_forms
|
|
||||||
.iter()
|
|
||||||
.map(|x| eval(x, env))
|
|
||||||
.collect::<Result<Vec<Expr>, RispError>>();
|
|
||||||
f(&args_eval?)
|
|
||||||
},
|
|
||||||
_ => Err(
|
|
||||||
RispError::Reason("first form must be a function".to_string())
|
|
||||||
),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Expr::Func(_) => Err(
|
|
||||||
RispError::Reason("unexpected form".to_string())
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn read_seq<'a>(tokens: &'a [String]) -> Result<(Expr, &'a [String]), RispError> {
|
fn read_seq<'a>(tokens: &'a [String]) -> Result<(Expr, &'a [String]), RispError> {
|
||||||
let mut res: Vec<Expr> = vec![];
|
let mut res: Vec<Expr> = vec![];
|
||||||
let mut xs = tokens;
|
let mut xs = tokens;
|
||||||
loop {
|
loop {
|
||||||
let (next_token, rest) = xs
|
let (next_token, rest) = xs
|
||||||
.split_first()
|
.split_first()
|
||||||
.ok_or(RispError::Reason("could not find closing `)`".to_string()))
|
.ok_or(RispError::Reason("could not find closing `)`".to_string()))?;
|
||||||
?;
|
if next_token == ")" {
|
||||||
if next_token == ")" {
|
return Ok((Expr::List(res), rest)); // skip `)`, head to the token after
|
||||||
return Ok((Expr::List(res), rest)) // skip `)`, head to the token after
|
}
|
||||||
|
let (exp, new_xs) = parse(&xs)?;
|
||||||
|
res.push(exp);
|
||||||
|
xs = new_xs;
|
||||||
}
|
}
|
||||||
let (exp, new_xs) = parse(&xs)?;
|
|
||||||
res.push(exp);
|
|
||||||
xs = new_xs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn slurp_expr() -> String {
|
fn slurp_expr() -> String {
|
||||||
let mut expr = String::new();
|
let mut expr = String::new();
|
||||||
|
|
||||||
io::stdin().read_line(&mut expr)
|
io::stdin()
|
||||||
.expect("Failed to read line");
|
.read_line(&mut expr)
|
||||||
|
.expect("Failed to read line");
|
||||||
|
|
||||||
expr
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let env = &mut default_env();
|
let env = &mut default_env();
|
||||||
loop {
|
loop {
|
||||||
print!("risp > ");
|
print!("risp > ");
|
||||||
let _= std::io::stdout().flush();
|
let _ = std::io::stdout().flush();
|
||||||
let expr = slurp_expr();
|
let expr = slurp_expr();
|
||||||
match parse_eval(expr, env) {
|
match parse_eval(expr, env) {
|
||||||
Ok(res) => println!("-> {}", res),
|
Ok(res) => println!("-> {}", res),
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
RispError::Reason(msg) => println!("X> {}", msg),
|
RispError::Reason(msg) => println!("X> {}", msg),
|
||||||
},
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,65 +1,57 @@
|
||||||
use crate::RispError;
|
use crate::evaluate::eval;
|
||||||
use crate::Expr;
|
|
||||||
use crate::eval;
|
|
||||||
use crate::Environ;
|
|
||||||
use crate::read_seq;
|
use crate::read_seq;
|
||||||
|
use crate::Environ;
|
||||||
|
use crate::Expr;
|
||||||
use crate::ParseFloatError;
|
use crate::ParseFloatError;
|
||||||
|
use crate::RispError;
|
||||||
|
|
||||||
pub
|
pub fn tokenize(expr: String) -> Vec<String> {
|
||||||
|
expr.replace("(", " ( ")
|
||||||
fn tokenize(expr: String) -> Vec<String> {
|
.replace(")", " ) ")
|
||||||
expr
|
.split_whitespace()
|
||||||
.replace("(", " ( ")
|
.map(|x| x.to_string())
|
||||||
.replace(")", " ) ")
|
.collect()
|
||||||
.split_whitespace()
|
|
||||||
.map(|x| x.to_string())
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub
|
pub fn parse<'a>(tokens: &'a [String]) -> Result<(Expr, &'a [String]), RispError> {
|
||||||
|
let (token, rest) = tokens
|
||||||
fn parse<'a>(tokens: &'a [String]) -> Result<(Expr, &'a [String]), RispError>{
|
.split_first()
|
||||||
let (token, rest) = tokens.split_first()
|
.ok_or(RispError::Reason("Could not get token".to_string()))?;
|
||||||
.ok_or(
|
match &token[..] {
|
||||||
RispError::Reason("Could not get token".to_string())
|
"(" => read_seq(rest),
|
||||||
)?;
|
")" => Err(RispError::Reason("unexpected `)`".to_string())),
|
||||||
match &token[..]{
|
_ => Ok((parse_atom(token), rest)),
|
||||||
"("=>{read_seq(rest)}
|
|
||||||
")"=>Err(RispError::Reason("unexpected `)`".to_string())),
|
|
||||||
_ => Ok((parse_atom(token), rest))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_list_of_floats(args: &[Expr]) -> Result<Vec<f64>, RispError> {
|
||||||
pub
|
args.iter().map(|x| parse_single_float(x)).collect()
|
||||||
|
|
||||||
fn parse_list_of_floats(args: &[Expr]) -> Result<Vec<f64>, RispError> {
|
|
||||||
args
|
|
||||||
.iter()
|
|
||||||
.map(|x| parse_single_float(x))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_single_float(exp: &Expr) -> Result<f64, RispError> {
|
fn parse_single_float(exp: &Expr) -> Result<f64, RispError> {
|
||||||
match exp {
|
match exp {
|
||||||
Expr::Number(num) => Ok(*num),
|
Expr::Number(num) => Ok(*num),
|
||||||
_ => Err(RispError::Reason("expected a number".to_string())),
|
_ => Err(RispError::Reason("expected a number".to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn parse_atom(token: &str) -> Expr {
|
fn parse_atom(token: &str) -> Expr {
|
||||||
let potential_float: Result<f64, ParseFloatError> = token.parse();
|
use Expr::*;
|
||||||
match potential_float {
|
match token.as_ref() {
|
||||||
Ok(v) => Expr::Number(v),
|
"true" => Bool(true),
|
||||||
Err(_) => Expr::Symbol(token.to_string().clone())
|
"false" => Bool(false),
|
||||||
}
|
_ => {
|
||||||
}pub
|
let potential_float: Result<f64, ParseFloatError> = token.parse();
|
||||||
fn parse_eval(expr: String, env: &mut Environ) -> Result<Expr, RispError> {
|
match potential_float {
|
||||||
let (parsed_exp, _) = parse(&tokenize(expr))?;
|
Ok(v) => Number(v),
|
||||||
let evaled_exp = eval(&parsed_exp, env)?;
|
Err(_) => Symbol(token.to_string().clone()),
|
||||||
|
}
|
||||||
Ok(evaled_exp)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn parse_eval(expr: String, env: &mut Environ) -> Result<Expr, RispError> {
|
||||||
|
let (parsed_exp, _) = parse(&tokenize(expr))?;
|
||||||
|
let evaled_exp = eval(&parsed_exp, env)?;
|
||||||
|
|
||||||
|
Ok(evaled_exp)
|
||||||
}
|
}
|
Loading…
Reference in a new issue