From 19d2c50ccbfe355e11fc64a9163c3c7f196564b9 Mon Sep 17 00:00:00 2001 From: malta895 Date: Sat, 14 Sep 2024 10:51:19 +0200 Subject: [PATCH] refactor parser in its module, start parser from scratch --- src/main.rs | 2 +- src/parser/lexer.rs | 2 +- src/parser/mod.rs | 120 +++++++-------------------------------- src/parser/parser.rs | 54 ++++++++++++++++++ src/parser/test_utils.rs | 0 5 files changed, 78 insertions(+), 100 deletions(-) create mode 100644 src/parser/parser.rs create mode 100644 src/parser/test_utils.rs diff --git a/src/main.rs b/src/main.rs index 82cd944..27be06f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ mod parser; fn main() { let buf = BufReader::new(std::io::stdin()); - match parser::JSONParser::check_valid(buf) { + match parser::check_valid(buf) { Err(e) => { eprintln!("{}", e); exit(1); diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 0e8e2c6..efaf53b 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -1,4 +1,4 @@ -use std::io::BufRead; +use std::io::{BufRead, Read}; use super::{error::JSONError, token::Token}; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 184864b..5352995 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,116 +1,40 @@ -use std::io::BufRead; +use std::io::{BufRead, Read}; mod token; use lexer::lex; +use parser::parse; use token::Token; mod error; use error::JSONError; mod lexer; +mod parser; -pub struct JSONParser { - reader: R, - tokens: Vec, - current_line: i64, -} - -impl JSONParser { - fn lex(&mut self) -> Result<(), JSONError> { - let tokens = lex(&mut self.reader); - match tokens { - Ok(tokens) => { - self.tokens = tokens; - Ok(()) - } - Err(lex_error) => Err(lex_error), - } - } - - fn new(reader: R) -> JSONParser { - JSONParser { - reader, - tokens: Vec::new(), - current_line: 1, - } - } - - fn build_json_err(&self, message: String) -> JSONError { - JSONError::new(message.clone(), self.current_line) - } - - pub fn check_valid(reader: R) -> Result<(), JSONError> { - let p = &mut Self::new(reader); - p.lex()?; - - dbg!(&p.tokens); - p.current_line = 1; - let mut obj_depth = 0; - let mut is_inside_array = false; - let mut is_json_ended = false; - let mut is_inside_literal = false; - let mut is_after_comma = false; - for token in &p.tokens { - match token { - Token::OpenBrace => { - is_after_comma = false; - obj_depth += 1; - } - Token::ClosedBrace => { - if obj_depth == 0 { - return Err(p.build_json_err(format!("Unexpected {} outside obj", token))); - } - if is_after_comma { - return Err(p.build_json_err(format!("Unexpected {} after comma", token))); - } - obj_depth -= 1; - if obj_depth == 0 { - is_json_ended = true; - } - } - Token::NewLine => { - // ignore for now - } - Token::Column => { - // ignore for now - } - Token::Comma => { - is_after_comma = true; - } - Token::StringLiteral(_) => { - is_after_comma = false; - } - Token::Number(_) | Token::BoolTrue | Token::BoolFalse | Token::Null => {} - Token::OpenBracket => {} - Token::ClosedBracket => {} - } - } - if !is_json_ended { - return Err(p.build_json_err(String::from("Unexpected EOF"))); - } - Ok(()) - } +pub fn check_valid(reader: R) -> Result<(), JSONError> { + let tokens = lex(reader)?; + parse(tokens) } #[cfg(test)] mod check_valid_tests { - use crate::parser::JSONParser; + use crate::parser::check_valid; #[test] fn should_not_report_error_for_obj() { - let res = JSONParser::check_valid("{}".as_bytes()); + let res = check_valid("{}".as_bytes()); assert_eq!(res, Ok(())); } #[test] fn should_report_error_for_not_closed_brace() { - let found_err = JSONParser::check_valid("{".as_bytes()).unwrap_err(); + let found_err = check_valid("{".as_bytes()).unwrap_err(); assert_eq!("Unexpected EOF: at line 1", found_err.to_string()) } #[test] fn should_report_error_for_closed_brace_outside_obj() { - let found_err = JSONParser::check_valid("}".as_bytes()).unwrap_err(); + let found_err = check_valid("}".as_bytes()).unwrap_err(); assert_eq!( "Unexpected '}' outside obj: at line 1", found_err.to_string() @@ -119,74 +43,74 @@ mod check_valid_tests { #[test] fn should_report_error_for_random_char() { - let found_err = JSONParser::check_valid("{a".as_bytes()).unwrap_err(); + let found_err = check_valid("{a".as_bytes()).unwrap_err(); assert_eq!("Unexpected 'a': at line 1", found_err.to_string()) } #[test] fn should_report_unexpected_eof_for_empty_file() { - let found_err = JSONParser::check_valid("".as_bytes()).unwrap_err(); + let found_err = check_valid("".as_bytes()).unwrap_err(); assert_eq!("Unexpected EOF: at line 1", found_err.to_string()) } #[test] fn should_not_report_error_for_new_line_at_the_end_of_file() { - let res = JSONParser::check_valid("{}\n".as_bytes()); + let res = check_valid("{}\n".as_bytes()); assert_eq!(Ok(()), res) } #[test] fn should_recognize_base_case() { - let res = JSONParser::check_valid("{\"\":\"\"}\n".as_bytes()); + let res = check_valid("{\"\":\"\"}\n".as_bytes()); assert_eq!(Ok(()), res) } #[test] fn should_recognize_base_case_with_key_val() { - let res = JSONParser::check_valid("{\"key\":\"value\"}\n".as_bytes()); + let res = check_valid("{\"key\":\"value\"}\n".as_bytes()); assert_eq!(Ok(()), res) } #[test] fn should_recognize_string_with_spaces() { - let res = JSONParser::check_valid("{ \"key\":\"va l\",\n \"ke y2\":\"val\"}".as_bytes()); + let res = check_valid("{ \"key\":\"va l\",\n \"ke y2\":\"val\"}".as_bytes()); assert_eq!(Ok(()), res) } #[test] fn should_recognize_number() { - let res = JSONParser::check_valid("{ \"key\": 123}".as_bytes()); + let res = check_valid("{ \"key\": 123}".as_bytes()); assert_eq!(Ok(()), res) } #[test] fn should_recognize_true() { - let res = JSONParser::check_valid("{ \"key\": true}".as_bytes()); + let res = check_valid("{ \"key\": true}".as_bytes()); assert_eq!(Ok(()), res) } #[test] fn should_recognize_false() { - let res = JSONParser::check_valid("{ \"key\": false}".as_bytes()); + let res = check_valid("{ \"key\": false}".as_bytes()); assert_eq!(Ok(()), res) } #[test] fn should_recognize_null() { - let res = JSONParser::check_valid("{ \"key\": null}".as_bytes()); + let res = check_valid("{ \"key\": null}".as_bytes()); assert_eq!(Ok(()), res) } #[test] fn should_recognize_empty_array() { - let res = JSONParser::check_valid("{ \"key\": []}".as_bytes()); + let res = check_valid("{ \"key\": []}".as_bytes()); assert_eq!(Ok(()), res) } #[test] fn should_recognize_nested_objects() { let res = - JSONParser::check_valid("{ \"key\": {\n\"inner_key\":\"inner_val\"\n}\n}".as_bytes()); + check_valid("{ \"key\": {\n\"inner_key\":\"inner_val\"\n}\n}".as_bytes()); assert_eq!(Ok(()), res) } } diff --git a/src/parser/parser.rs b/src/parser/parser.rs new file mode 100644 index 0000000..991e453 --- /dev/null +++ b/src/parser/parser.rs @@ -0,0 +1,54 @@ +use super::{error::JSONError, token::Token}; + +pub fn parse(tokens: Vec)-> Result<(), JSONError>{ + if tokens.len() == 1 && tokens[0] == Token::OpenBrace { + return Err(JSONError::new("Unexpected EOF".to_string(), 1)); + } + Ok(()) +} + +#[cfg(test)] +mod test_parser_pass{ + use crate::parser::token::Token; + macro_rules! test_parser_passes { + ($($name:ident: $value:expr,)*) => { + use super::parse; + $( + #[test] + fn $name() { + let input = $value; + assert_eq!((), parse(input).unwrap()); + } + )* + } + } + + test_parser_passes! { + with_closed_open_brace: vec![Token::OpenBrace, Token::ClosedBrace], + } +} + +#[cfg(test)] +mod test_parser_failure { + use crate::parser::{token::Token, error::JSONError}; + macro_rules! test_parser_fails { + ($($name:ident: $value:expr,)*) => { + use super::parse; + $( + #[test] + fn $name() { + let (input, expected_err) = $value; + assert_eq!(expected_err, parse(input).unwrap_err()); + } + )* + } + } + + test_parser_fails! { + with_only_open_brace: ( + vec![Token::OpenBrace], + JSONError::new("Unexpected EOF".to_string(), 1), + ), + } +} + diff --git a/src/parser/test_utils.rs b/src/parser/test_utils.rs new file mode 100644 index 0000000..e69de29