diff options
author | Bryan Newbold <bnewbold@robocracy.org> | 2021-10-24 11:51:03 -0700 |
---|---|---|
committer | Bryan Newbold <bnewbold@robocracy.org> | 2021-10-24 11:51:03 -0700 |
commit | 76a5c98ef5588e94301f2d1b44b51907e5004abe (patch) | |
tree | 28e62f093f1950c0db2b2e51328aaf9ef6417350 /src/sexpr.rs | |
parent | 5f501b3654d6b36e850044ba492dd7bc7ee56438 (diff) | |
download | casual-76a5c98ef5588e94301f2d1b44b51907e5004abe.tar.gz casual-76a5c98ef5588e94301f2d1b44b51907e5004abe.zip |
more progress
Diffstat (limited to 'src/sexpr.rs')
-rw-r--r-- | src/sexpr.rs | 73 |
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 { } } } - |