From bbd7ab9bb44e99a0cb2bd1a8ea9a5336a08117dd Mon Sep 17 00:00:00 2001 From: Shigeru Hagiwara Date: Sun, 30 Jun 2024 17:10:27 +0900 Subject: [PATCH] ex print command --- src/command/base.rs | 9 +- src/command/commands/mod.rs | 1 + src/command/commands/print.rs | 22 +++ src/data.rs | 48 ++++++ src/ex/lexer.rs | 41 +++-- src/ex/parser.rs | 298 ++++++++++++++++++++++++---------- src/main.rs | 1 + 7 files changed, 308 insertions(+), 112 deletions(-) create mode 100644 src/command/commands/print.rs create mode 100644 src/data.rs diff --git a/src/command/base.rs b/src/command/base.rs index 85bcffe..9d1d858 100644 --- a/src/command/base.rs +++ b/src/command/base.rs @@ -2,32 +2,39 @@ use std::any::Any; use crossterm::event::{KeyCode, KeyModifiers}; -use crate::{editor::Editor, generic_error::GenericResult}; +use crate::{data::LineRange, editor::Editor, generic_error::GenericResult}; pub trait Command { fn execute(&mut self, editor: &mut Editor) -> GenericResult<()>; + fn is_reusable(&self) -> bool { true } + fn is_modeful(&self) -> bool { false } + fn is_undoable(&self) -> bool { false } + fn undo(&mut self, editor: &mut Editor) -> GenericResult<()> { let _ = editor; // do nothing Ok(()) } + fn redo(&mut self, editor: &mut Editor) -> GenericResult>> { let _ = editor; // do nothing Ok(None) } + fn set_text(&mut self, _text: String) { // do nothing } + fn as_any(&self) -> &dyn Any; } diff --git a/src/command/commands/mod.rs b/src/command/commands/mod.rs index d684de2..1bcb9d9 100644 --- a/src/command/commands/mod.rs +++ b/src/command/commands/mod.rs @@ -7,3 +7,4 @@ pub mod esc; pub mod delete; pub mod undo; pub mod append; +pub mod print; diff --git a/src/command/commands/print.rs b/src/command/commands/print.rs new file mode 100644 index 0000000..768e7e1 --- /dev/null +++ b/src/command/commands/print.rs @@ -0,0 +1,22 @@ +use std::any::Any; + +use crate::command::base::Command; +use crate::data::LineRange; +use crate::editor::Editor; +use crate::generic_error::GenericResult; + +pub struct PrintCommand { + pub line_range: LineRange +} + +impl Command for PrintCommand { + fn execute(&mut self, editor: &mut Editor) -> GenericResult<()> { + // TODO: Implement PrintCommand + log::info!("PrintCommand execute"); + Ok(()) + } + + fn as_any(&self) -> &dyn Any { + self + } +} diff --git a/src/data.rs b/src/data.rs new file mode 100644 index 0000000..0c56658 --- /dev/null +++ b/src/data.rs @@ -0,0 +1,48 @@ +#[derive(Debug, PartialEq, Clone)] +pub enum TokenType { + Colon, + Command, + Option, + Number, + Symbol, + Pattern, + AddressPattern, + Replacement, + Filename, + Separator, + EndOfInput, + Illegal, +} + +#[derive(Debug, Clone)] +pub struct Token { + pub token_type: TokenType, + pub lexeme: String, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct Pattern { + pub pattern: String, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum SimpleLineAddressType { + LineNumber(usize), + CurrentLine, + FirstLine, + LastLine, + AllLines, + Pattern(Pattern) +} + +#[derive(Debug, PartialEq, Clone)] +pub enum LineAddressType { + Absolute(SimpleLineAddressType), + Relative(SimpleLineAddressType, isize), +} + +#[derive(Debug, PartialEq, Clone)] +pub struct LineRange { + pub start: LineAddressType, + pub end: LineAddressType, +} diff --git a/src/ex/lexer.rs b/src/ex/lexer.rs index 9048fd8..d85184f 100644 --- a/src/ex/lexer.rs +++ b/src/ex/lexer.rs @@ -1,24 +1,5 @@ -#[derive(Debug, PartialEq)] -pub enum TokenType { - Colon, - Command, - Option, - Number, - Symbol, - Pattern, - AddressPattern, - Replacement, - Filename, - Separator, - EndOfInput, - Illegal, -} - -#[derive(Debug)] -pub struct Token { - pub token_type: TokenType, - pub lexeme: String, -} +use crate::data::TokenType; +use crate::data::Token; #[derive(Debug, PartialEq)] enum SubstitutionCommandState { @@ -521,4 +502,22 @@ mod tests { assert_eq!(tokens[2].lexeme, "q"); assert_eq!(tokens[3].token_type, TokenType::EndOfInput); } + + #[test] + fn test_tokenize_print_with_line_addresses() { + let input = ":1,2p"; + let tokens = tokenize(input); + assert_eq!(tokens.len(), 6); + assert_eq!(tokens[0].token_type, TokenType::Colon); + assert_eq!(tokens[0].lexeme, ":"); + assert_eq!(tokens[1].token_type, TokenType::Number); + assert_eq!(tokens[1].lexeme, "1"); + assert_eq!(tokens[2].token_type, TokenType::Separator); + assert_eq!(tokens[2].lexeme, ","); + assert_eq!(tokens[3].token_type, TokenType::Number); + assert_eq!(tokens[3].lexeme, "2"); + assert_eq!(tokens[4].token_type, TokenType::Command); + assert_eq!(tokens[4].lexeme, "p"); + assert_eq!(tokens[5].token_type, TokenType::EndOfInput); + } } diff --git a/src/ex/parser.rs b/src/ex/parser.rs index 20e4a57..d4676ae 100644 --- a/src/ex/parser.rs +++ b/src/ex/parser.rs @@ -1,13 +1,17 @@ -use log::info; use std::ops::BitOr; use crate::command::base::Command; +use crate::data::LineAddressType; +use crate::data::LineRange; +use crate::data::Pattern; +use crate::data::SimpleLineAddressType; +use crate::data::Token; +use crate::data::TokenType; use crate::ex::lexer; use crate::generic_error::GenericError; use crate::command::commands::exit; - -use super::lexer::TokenType; +use crate::command::commands::print; enum MyOption { Some(T), @@ -35,43 +39,29 @@ impl BitOr for MyOption> { } } -pub enum SimpleLineAddressType { - LineNumber(usize), - CurrentLine, - LastLine, - AllLines, -} - -pub enum LineAddressType { - Absolute(SimpleLineAddressType), - Relative(SimpleLineAddressType, isize), -} - -pub struct LineRange { - start: LineAddressType, - end: LineAddressType, -} - pub struct Parser { - tokens: Vec, - token: MyOption, - command: MyOption>, - line_range: MyOption, + tokens: Vec, + token_opt: MyOption, + stack: Vec, + command_opt: MyOption>, + line_range_opt: MyOption, } impl Parser { pub fn new(input: &str) -> Self { let tokens = lexer::tokenize(input); - info!("tokens {:?}", tokens); + println!("tokens {:?}", tokens); Parser { tokens, - token: MyOption::None, - command: MyOption::None, - line_range: MyOption::None, + token_opt: MyOption::None, + stack: Vec::new(), + command_opt: MyOption::None, + line_range_opt: MyOption::None, } } pub fn parse(&mut self) -> Result, GenericError> { + self.get_symbol(); self.command() } @@ -83,11 +73,22 @@ impl Parser { } } - fn get_symbol(&mut self) -> MyOption { + fn push(&mut self, token: Token) { + self.stack.push(token); + } + + fn pop(&mut self) -> MyOption { + if self.stack.len() > 0 { + return MyOption::Some(self.stack.pop().unwrap()); + } + MyOption::None + } + + fn get_symbol(&mut self) { if self.tokens.len() > 0 { - return MyOption::Some(self.tokens.remove(0)); + self.token_opt = MyOption::Some(self.tokens.remove(0)); } else { - return MyOption::Some(lexer::Token { + self.token_opt = MyOption::Some(Token { token_type: TokenType::EndOfInput, lexeme: "".to_string(), }); @@ -98,21 +99,163 @@ impl Parser { format!("Error: {}", message).into() } - fn accept(&mut self, token_type: lexer::TokenType) -> bool { - if let MyOption::Some(token) = &self.token { + fn accept(&mut self, token_type: TokenType, lexeme: &str) -> bool { + let expected_token = Token { + token_type, + lexeme: lexeme.to_string(), + }; + if let MyOption::Some(token) = &self.token_opt { + if token.token_type == expected_token.token_type + && token.lexeme == expected_token.lexeme + { + self.push(token.clone()); + self.get_symbol(); + return true; + } + } + false + } + + fn accept_type(&mut self, token_type: TokenType) -> bool { + if let MyOption::Some(token) = &self.token_opt { if token.token_type == token_type { - self.token = self.get_symbol(); + self.push(token.clone()); + self.get_symbol(); return true; } } false } - fn expect(&mut self, token_type: lexer::TokenType) -> Result<(), GenericError> { - if self.accept(token_type) { - return Ok(()); + fn complex_command(&mut self) -> Result>, GenericError> { + let line_range = if let MyOption::Some(range) = self.line_range()? { + range + } else { + LineRange { + start: LineAddressType::Absolute(SimpleLineAddressType::CurrentLine), + end: LineAddressType::Absolute(SimpleLineAddressType::CurrentLine), + } + }; + let command_opt = self.display_command(line_range)? | self.substitute_command()?; + if let MyOption::Some(command) = command_opt { + return Ok(MyOption::Some(command)); + } + Ok(MyOption::None) + } + + fn display_command(&mut self, line_range: LineRange) -> Result>, GenericError> { + if self.accept(TokenType::Command, "p") { + let print_command = print::PrintCommand { + line_range + }; + return Ok(MyOption::Some(Box::new(print_command))); + } + Ok(MyOption::None) + } + + fn line_range(&mut self) -> Result, GenericError> { + // line_address "," line_address + // | line_address "," pattern + // | pattern "," line_address + // | pattern "," pattern + // | line_address + // | pattern + if let MyOption::Some(start_line_address) = self.line_address()? { + if self.accept(TokenType::Separator, ",") { + self.pop(); + if let MyOption::Some(end_line_address) = self.line_address()? { + return Ok(MyOption::Some(LineRange { + start: start_line_address, + end: end_line_address, + })); + } else if let MyOption::Some(pattern) = self.pattern()? { + let end_line_address = + LineAddressType::Absolute(SimpleLineAddressType::Pattern(pattern)); + return Ok(MyOption::Some(LineRange { + start: start_line_address, + end: end_line_address, + })); + } + } else { + return Ok(MyOption::Some(LineRange { + start: start_line_address.clone(), + end: start_line_address.clone(), + })); + } + } else if let MyOption::Some(pattern1) = self.pattern()? { + if self.accept(TokenType::Separator, ",") { + self.pop(); + if let MyOption::Some(end_line_address) = self.line_address()? { + return Ok(MyOption::Some(LineRange { + start: LineAddressType::Absolute(SimpleLineAddressType::Pattern(pattern1)), + end: end_line_address, + })); + } else if let MyOption::Some(pattern2) = self.pattern()? { + return Ok(MyOption::Some(LineRange { + start: LineAddressType::Absolute(SimpleLineAddressType::Pattern(pattern1)), + end: LineAddressType::Absolute(SimpleLineAddressType::Pattern(pattern2)), + })); + } + } else { + return Ok(MyOption::Some(LineRange { + start: LineAddressType::Absolute(SimpleLineAddressType::Pattern( + pattern1.clone(), + )), + end: LineAddressType::Absolute(SimpleLineAddressType::Pattern( + pattern1.clone(), + )), + })); + } + } + Ok(MyOption::None) + } + + fn line_address(&mut self) -> Result, GenericError> { + // number, "$", "^", ".", "%" + if self.accept_type(TokenType::Number) { + if let MyOption::Some(token) = self.pop() { + let number = token.lexeme.clone(); + println!("number {:?}", number); + return Ok(MyOption::Some(LineAddressType::Absolute( + SimpleLineAddressType::LineNumber(number.parse().unwrap()), + ))); + } + } else if self.accept(TokenType::Symbol, "$") { + self.pop(); + return Ok(MyOption::Some(LineAddressType::Absolute( + SimpleLineAddressType::LastLine, + ))); + } else if self.accept(TokenType::Symbol, "^") { + self.pop(); + return Ok(MyOption::Some(LineAddressType::Absolute( + SimpleLineAddressType::FirstLine, + ))); + } else if self.accept(TokenType::Symbol, ".") { + self.pop(); + return Ok(MyOption::Some(LineAddressType::Absolute( + SimpleLineAddressType::CurrentLine, + ))); + } else if self.accept(TokenType::Symbol, "%") { + self.pop(); + return Ok(MyOption::Some(LineAddressType::Absolute( + SimpleLineAddressType::AllLines, + ))); } - Err(self.error("Unexpected token")) + Ok(MyOption::None) + } + + fn pattern(&mut self) -> Result, GenericError> { + if self.accept_type(TokenType::Pattern) { + if let MyOption::Some(token) = &self.token_opt { + let pattern = token.lexeme.clone(); + return Ok(MyOption::Some(Pattern { pattern })); + } + } + Ok(MyOption::None) + } + + fn substitute_command(&mut self) -> Result>, GenericError> { + Ok(MyOption::None) } fn simple_command(&mut self) -> Result>, GenericError> { @@ -126,7 +269,7 @@ impl Parser { fn q_command(&mut self) -> Result>, GenericError> { // tokens が "q" は Ok(Some(Box::new(ExitCommand {}))) を返す。 if self.tokens.len() == 2 { - if self.tokens[0].token_type == lexer::TokenType::Command { + if self.tokens[0].token_type == TokenType::Command { if self.tokens[0].lexeme == "q" { return Ok(MyOption::Some(Box::new(exit::ExitCommand {}))); } @@ -138,8 +281,8 @@ impl Parser { fn wq_command(&mut self) -> Result>, GenericError> { // tokens が "w", "q" は Ok(Some(Box::new(ExitWithSaveCommand {}))) を返す。 if self.tokens.len() == 3 { - if self.tokens[0].token_type == lexer::TokenType::Command - && self.tokens[1].token_type == lexer::TokenType::Command + if self.tokens[0].token_type == TokenType::Command + && self.tokens[1].token_type == TokenType::Command { if self.tokens[0].lexeme == "w" && self.tokens[1].lexeme == "q" { return Ok(MyOption::Some(Box::new(exit::ExitWithSaveCommand {}))); @@ -148,55 +291,6 @@ impl Parser { } Ok(MyOption::None) } - - fn complex_command(&mut self) -> Result>, GenericError> { - Ok(MyOption::None) - } - - // fn complex_command(tokens: &Vec) -> Result>, GenericError> { - // let command_opt = - // display_command(tokens)? | substitute_command(tokens)?; - // if let MyOption::Some(command) = command_opt { - // return Ok(MyOption::Some(command)); - // } - // Ok(MyOption::None) - // } - - // fn display_command(tokens: &Vec) -> Result>, GenericError> { - // let command_opt = - // line_range(tokens)? & print_command(tokens)?; - // if let MyOption::Some(command) = command_opt { - // return Ok(MyOption::Some(command)); - // } - // Ok(MyOption::None) - // } - - // fn line_range(tokens: &Vec) -> Result, GenericError> { - // let result = - // line_address(tokens)? & comma(tokens)? & line_address(tokens)? - // | pattern(tokens)? & comma(tokens)? & line_address(tokens)? - // | line_address(tokens)? & comma(tokens)? & pattern(tokens)? - // | pattern(tokens)? & comma(tokens)? & pattern(tokens)?; - // | line_address(tokens)?; - // if let MyOption::Some(line_range) = result { - // return Ok(MyOption::Some(line_range)); - // } - // Ok(MyOption::None) - // } - - // fn line_address(tokens: &Vec) -> Result, GenericError> { - // if tokens.len() == 1 { - // if tokens[0].token_type == lexer::TokenType::Number { - // let line_number = tokens[0].lexeme.parse::().unwrap(); - // return Ok(MyOption::Some(LineAddressType::Absolute(SimpleLineAddressType::LineNumber(line_number)))); - // } - // } - // Ok(MyOption::None) - // } - - // fn substitute_command(tokens: &Vec) -> Result>, GenericError> { - // Ok(MyOption::None) - // } } #[cfg(test)] @@ -210,4 +304,28 @@ mod tests { let command = parser.parse().unwrap(); assert!(command.is::()); } + + #[test] + fn test_parse_print_command() { + let input = "p"; + let mut parser = Parser::new(input); + let command = parser.parse().unwrap(); + assert!(command.is::()); + } + + #[test] + fn test_parse_print_with_line_address() { + let input = "1,2p"; + let mut parser = Parser::new(input); + let command = parser.parse().unwrap(); + assert!(command.is::()); + let print_command = command.downcast_ref::().unwrap(); + assert_eq!( + print_command.line_range, + LineRange { + start: LineAddressType::Absolute(SimpleLineAddressType::LineNumber(1)), + end: LineAddressType::Absolute(SimpleLineAddressType::LineNumber(2)), + } + ); + } } diff --git a/src/main.rs b/src/main.rs index 67705af..e7ebe7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod data; mod buffer; mod command; mod editor;