summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominick Allen <dominick.allen1989@gmail.com>2020-06-28 19:50:35 -0500
committerDominick Allen <dominick.allen1989@gmail.com>2020-06-28 19:50:35 -0500
commit2ffb5357e0e35d415311a40eea14e9cc99dd54ab (patch)
tree0410800cd74956d294a76ef6e47d527b0c1adeed
parent3eb53c36123c4a8a8f336c255a9d5a7b44ca922c (diff)
Improve read functionality.
-rw-r--r--src/lib/eval/arith.rs5
-rw-r--r--src/lib/tokenize.rs5
-rw-r--r--src/main.rs92
3 files changed, 69 insertions, 33 deletions
diff --git a/src/lib/eval/arith.rs b/src/lib/eval/arith.rs
index fe3a06b..d7d53e0 100644
--- a/src/lib/eval/arith.rs
+++ b/src/lib/eval/arith.rs
@@ -1,10 +1,11 @@
use std::ops::{Add, Sub, Mul, Div};
use super::super::types::Type;
+use super::super::types::FloatType;
use super::super::types::Number;
fn apply_arithmetic(
func_i: fn(isize, isize) -> isize,
- func_f: fn(f32, f32) -> f32,
+ func_f: fn(FloatType, FloatType) -> FloatType,
operand_a: &Type,
operand_b: &Type) -> Result<Type, String> {
@@ -17,7 +18,7 @@ fn apply_arithmetic(
(Type::Number(Number::Int(i)), Type::Number(Number::Float(f))) |
(Type::Number(Number::Float(f)), Type::Number(Number::Int(i))) => {
- Ok(Type::Number(Number::Float(func_f(*f, *i as f32))))
+ Ok(Type::Number(Number::Float(func_f(*f, *i as FloatType))))
},
(Type::Number(Number::Int(a)), Type::Number(Number::Int(b))) => {
diff --git a/src/lib/tokenize.rs b/src/lib/tokenize.rs
index 0a50036..483536f 100644
--- a/src/lib/tokenize.rs
+++ b/src/lib/tokenize.rs
@@ -1,4 +1,5 @@
use super::types::Type;
+use super::types::FloatType;
use super::types::Number;
use super::types::Op;
use super::sexpr::SExpr;
@@ -242,7 +243,7 @@ pub fn is_int(word: &str) -> MaybeToken {
}
pub fn is_float(word: &str) -> MaybeToken {
- match word.parse::<f32>() {
+ match word.parse::<FloatType>() {
Ok(x) => (Some(Ok(Token::Value(Type::Number(Number::Float(x))))), word.len()),
_ => (None, 0)
}
@@ -268,7 +269,7 @@ pub fn descend(tokenstream: &mut TokenStream) -> Result<SExpr, String> {
let token = match tokenstream.next() {
Some(Ok(x)) => x,
Some(Err(f)) => return Err(f),
- None => panic!("Empty string".to_string())
+ None => return Err("Unexpected end of expression".to_string())
};
match token {
diff --git a/src/main.rs b/src/main.rs
index c2f9881..0116f78 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,33 +8,59 @@ use rustyline::Editor;
use lib::environment::Environment;
-fn read<T: rustyline::Helper>(rl: &mut Editor<T>) -> Option<String> {
- let readline = rl.readline(">> ");
- match readline {
- Ok(line) => {
- rl.add_history_entry(line.as_str());
- Some(line)
- },
- Err(ReadlineError::Interrupted) => {
- println!("CTRL-C");
- None
- },
- Err(ReadlineError::Eof) => {
- println!("CTRL-D");
- None
- },
- Err(err) => {
- println!("Error: {:?}", err);
- None
+const EXIT_STRINGS: &[&str; 3] = &[",q", "exit", "quit"];
+
+fn read<T: rustyline::Helper>(rl: &mut Editor<T>) -> Result<String, String> {
+ let mut readline = rl.readline(">> ");
+ let mut full_line = String::new();
+
+ fn count_parens(s: &str) -> Result<bool, ()> {
+ let mut lcount = 0;
+ let mut rcount = 0;
+ for c in s.chars() {
+ match c {
+ '(' => lcount += 1,
+ ')' => rcount += 1,
+ _ => {}
+ }
+ if rcount > lcount {
+ return Err(())
+ }
+ }
+ return Ok(lcount == rcount)
+ }
+
+ let mut loop_count = 0;
+ loop {
+ match readline {
+ Ok(line) => {
+ full_line.push_str(&line);
+ match count_parens(&full_line) {
+ Ok(true) => return Ok(full_line),
+ Ok(false) => readline = rl.readline("... "),
+ Err(_) => return Err("unexpected \")\"".to_string())
+ }
+ },
+ Err(ReadlineError::Interrupted) => {
+ return Err("user interrupt".to_string())
+ },
+ Err(ReadlineError::Eof) => {
+ if loop_count > 0 {
+ return Err("end of file".to_string());
+ } else {
+ return Ok(EXIT_STRINGS[0].to_string());
+ }
+ },
+ Err(err) => {
+ return Err(format!("{:?}", err));
+ }
}
+ loop_count += 1
}
}
fn means_exit(input: &str) -> bool {
- match input {
- "exit" | "quit" | ",q" => true,
- _ => false
- }
+ EXIT_STRINGS.iter().any(|&s| s == input)
}
fn eval(env: &mut Environment, input: &str) -> String {
@@ -45,8 +71,8 @@ fn eval(env: &mut Environment, input: &str) -> String {
let res = lib::eval::eval(&sexp, env);
match res {
- Ok(x) => format!("{:?}", x),
- Err(f) => f
+ Ok(x) => format!("{}", x),
+ Err(f) => format!("Error: {}", f)
}
}
@@ -61,12 +87,20 @@ fn main() {
}
loop {
let input_line = read(&mut rl);
- let line = match input_line {
- None => break,
- Some(expr) if means_exit(&expr) => break,
- Some(expr) => expr
+ match input_line {
+ Err(e) => {
+ println!("Error: {}", e);
+ continue;
+ }
+ Ok(expr) => {
+ if means_exit(&expr) {
+ break;
+ }
+ rl.add_history_entry(expr.as_str());
+ println!("{}", eval(&mut env, &expr));
+ }
};
- println!("{}", eval(&mut env, &line));
+
}
rl.save_history(hist_file).unwrap();
}