aboutsummaryrefslogtreecommitdiffstats
path: root/src/sexpr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sexpr.rs')
-rw-r--r--src/sexpr.rs73
1 files changed, 38 insertions, 35 deletions
diff --git a/src/sexpr.rs b/src/sexpr.rs
index d761192..7312b68 100644
--- a/src/sexpr.rs
+++ b/src/sexpr.rs
@@ -9,11 +9,11 @@
* in a dependency.
*/
-use std::str;
use std::fmt;
-use std::io::Read;
use std::fs::File;
+use std::io::Read;
use std::path::Path;
+use std::str;
//////////// Types and Constants
@@ -30,7 +30,7 @@ pub enum SExpr {
//////////// Lexing, Parsing, and Printing
-fn is_whitespace(c: char) -> bool{
+fn is_whitespace(c: char) -> bool {
" \t\r\n".find(c) != None
}
@@ -47,11 +47,15 @@ fn is_valid_identifier(s: &str) -> bool {
if s == "." {
return false;
}
+ if s == "-" {
+ return true;
+ }
if s.starts_with("-") || s.starts_with("'") {
return false;
}
for (i, c) in s.chars().enumerate() {
- if !( c.is_alphabetic() || "!$%&*+-./:<=>?@^_~".find(c) != None || (c.is_numeric() && i > 0) ) {
+ if !(c.is_alphabetic() || "!$%&*+-./:<=>?@^_~".find(c) != None || (c.is_numeric() && i > 0))
+ {
return false;
}
}
@@ -64,17 +68,17 @@ fn is_valid_identifier(s: &str) -> bool {
*/
pub fn sexpr_tokenize<'a>(raw_str: &'a str) -> Result<Vec<&'a str>, String> {
let mut ret = Vec::<&str>::new();
- let mut food: usize = 0; // "how many chars of current token have we read?"
+ let mut food: usize = 0; // "how many chars of current token have we read?"
let mut quoted: bool = false;
let mut commented: bool = false;
for (i, c) in raw_str.chars().enumerate() {
if quoted {
// Safe to look-back a character here because quoted can't be true for first char
- if c == '"' && raw_str.chars().collect::<Vec<char>>()[i-1] != '\\' {
- ret.push(&raw_str[i-food-1..i+1]);
+ if c == '"' && raw_str.chars().collect::<Vec<char>>()[i - 1] != '\\' {
+ ret.push(&raw_str[i - food - 1..i + 1]);
quoted = false;
food = 0;
- } else if raw_str.len() == i+1 {
+ } else if raw_str.len() == i + 1 {
return Err(format!("unmatched quote char"));
} else {
food += 1;
@@ -85,7 +89,7 @@ pub fn sexpr_tokenize<'a>(raw_str: &'a str) -> Result<Vec<&'a str>, String> {
}
} else if c == ';' {
if food > 0 {
- ret.push(&raw_str[i-food..i]);
+ ret.push(&raw_str[i - food..i]);
}
commented = true;
food = 0;
@@ -96,15 +100,15 @@ pub fn sexpr_tokenize<'a>(raw_str: &'a str) -> Result<Vec<&'a str>, String> {
quoted = true;
} else if is_whitespace(c) || is_seperator(c) {
if food > 0 {
- ret.push(&raw_str[i-food..i]);
+ ret.push(&raw_str[i - food..i]);
}
if is_seperator(c) {
- ret.push(&raw_str[i..i+1]);
+ ret.push(&raw_str[i..i + 1]);
}
food = 0;
- } else if raw_str.len() == i+1 {
+ } else if raw_str.len() == i + 1 {
// end of input
- ret.push(&raw_str[i-food..]);
+ ret.push(&raw_str[i - food..]);
} else {
food += 1;
}
@@ -119,24 +123,23 @@ pub fn sexpr_tokenize<'a>(raw_str: &'a str) -> Result<Vec<&'a str>, String> {
* This function takes a token (still a string) and parses it into a single SExpression
*/
fn sexpr_parse_token(token: &str) -> Result<SExpr, String> {
-
// Is it a constant?
match token {
"#t" => return Ok(SExpr::SBoolean(true)),
"#f" => return Ok(SExpr::SBoolean(false)),
- _ => ()
+ _ => (),
}
// Try to parse as an integer
match token.parse::<i64>() {
Ok(x) => return Ok(SExpr::SInteger(x)),
- Err(_) => ()
+ Err(_) => (),
}
// Try to parse as floating-point number
match token.parse::<f64>() {
Ok(x) => return Ok(SExpr::SFloat(x)),
- Err(_) => ()
+ Err(_) => (),
}
// Is it a string?
@@ -158,7 +161,7 @@ fn sexpr_parse_token(token: &str) -> Result<SExpr, String> {
*/
pub fn sexpr_parse(tokens: &Vec<&str>, depth: u32) -> Result<(Vec<SExpr>, usize), String> {
let mut i: usize = 0;
- if tokens.len() == 0 {
+ if tokens.len() == 0 {
return Ok((vec![SExpr::SNull], 0));
} else if tokens.len() == 1 {
let expr = sexpr_parse_token(tokens[0])?;
@@ -171,25 +174,24 @@ pub fn sexpr_parse(tokens: &Vec<&str>, depth: u32) -> Result<(Vec<SExpr>, usize)
match tokens[i] {
"(" => {
// "Read ahead" to check for empty tuple
- if i+1 < tokens.len() && tokens[i+1] == ")" {
+ if i + 1 < tokens.len() && tokens[i + 1] == ")" {
ret.push(SExpr::SNull);
i += 1;
parsed += 1;
} else {
- let (expr_list, skip) = sexpr_parse(&tokens[i+1..].to_vec(), depth+1)?;
+ let (expr_list, skip) = sexpr_parse(&tokens[i + 1..].to_vec(), depth + 1)?;
i += skip;
parsed += skip;
ret.push(SExpr::SList(expr_list));
}
- },
+ }
")" => {
if depth == 0 {
return Err(format!("missing an open bracket"));
}
return Ok((ret, parsed));
- },
- "'" => {
- },
+ }
+ "'" => {}
token => {
let expr = sexpr_parse_token(token)?;
ret.push(expr);
@@ -215,25 +217,27 @@ pub fn sexpr_repr(ast: &SExpr) -> Result<String, String> {
&SExpr::SBoolean(false) => Ok("#f".to_string()),
&SExpr::SInteger(num) => Ok(format!("{}", num).to_string()),
&SExpr::SFloat(num) => Ok(format!("{}", num).to_string()),
- &SExpr::SString(ref s)=> Ok(s.clone()),
- &SExpr::SIdentifier(ref s)=> Ok(s.to_string()),
+ &SExpr::SString(ref s) => Ok(s.clone()),
+ &SExpr::SIdentifier(ref s) => Ok(s.to_string()),
&SExpr::SList(ref list) => {
- let elements: Vec<String> = list.iter().map(|ref el| sexpr_repr(&el).unwrap()).collect();
+ let elements: Vec<String> =
+ list.iter().map(|ref el| sexpr_repr(&el).unwrap()).collect();
Ok(format!("({})", elements.join(" ")))
- },
- }
+ }
+ };
}
pub fn sexpr_parse_file(fpath: &Path) -> Result<(), String> {
-
let mut raw_bytes: Vec<u8> = Vec::new();
- let mut f = File::open(fpath)
- .expect(&format!("couldn't open file: {}", &fpath.to_str().unwrap()));
+ let mut f =
+ File::open(fpath).expect(&format!("couldn't open file: {}", &fpath.to_str().unwrap()));
f.read_to_end(&mut raw_bytes)
.expect(&format!("couldn't read file: {}", &fpath.to_str().unwrap()));
- let contents = String::from_utf8(raw_bytes)
- .expect(&format!("UTF-8 decode error reading file: {}", &fpath.to_str().unwrap()));
+ let contents = String::from_utf8(raw_bytes).expect(&format!(
+ "UTF-8 decode error reading file: {}",
+ &fpath.to_str().unwrap()
+ ));
let tokens = sexpr_tokenize(&contents)?;
let (_ast_list, _) = sexpr_parse(&tokens, 0)?;
@@ -256,4 +260,3 @@ impl fmt::Display for SExpr {
}
}
}
-