From ed885b0f8106c0ee2bb66c33fb621b3b7cc89b52 Mon Sep 17 00:00:00 2001 From: Lewis Dale Date: Sat, 21 Jan 2023 08:40:11 +0000 Subject: [PATCH] Move command parsers into parsers module --- src/basic.rs | 80 ++++++++++------------------------------- src/parsers.rs | 1 + src/parsers/commands.rs | 49 +++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 62 deletions(-) create mode 100644 src/parsers/commands.rs diff --git a/src/basic.rs b/src/basic.rs index 03f8c26..7a400ce 100644 --- a/src/basic.rs +++ b/src/basic.rs @@ -1,11 +1,8 @@ use std::collections::HashMap; -use nom::{ - branch::alt, bytes::complete::tag, character::complete::u64 as ccu64, combinator::map, - multi::separated_list0, sequence::terminated, IResult, -}; +use nom::{bytes::complete::tag, multi::separated_list0, IResult}; -use crate::parsers::{generic, variables}; +use crate::parsers::commands; pub type Line = (usize, Command); @@ -115,11 +112,22 @@ impl Program { }; } } + + fn read(i: &str) -> IResult<&str, Self> { + let (i, lines) = separated_list0(tag("\n"), commands::parse_line)(i)?; + let mut node = Node::None; + + for line in lines.iter() { + node.push(line.clone()); + } + + Ok((i, Program::new(node))) + } } impl From<&str> for Program { fn from(value: &str) -> Self { - let (_, program) = read_program(value).unwrap(); + let (_, program) = Self::read(value).unwrap(); program } } @@ -139,65 +147,13 @@ impl Iterator for Program { } } -fn match_command(i: &str) -> IResult<&str, &str> { - alt((tag("PRINT"), tag("GO TO"), tag("LET"), tag("REM")))(i) -} - -fn parse_print_command(i: &str) -> IResult<&str, PrintOutput> { - alt(( - map( - alt(( - variables::parse_str_variable_name, - variables::parse_int_variable_name, - )), - PrintOutput::Variable, - ), - map(generic::read_string, PrintOutput::Value), - ))(i) -} - -fn parse_command(i: &str) -> IResult<&str, Command> { - let (i, command): (&str, &str) = match_command(i).unwrap_or((i, "")); - let (i, _) = tag(" ")(i)?; - - let (i, cmd) = match command { - "PRINT" => map(parse_print_command, Command::Print)(i)?, - "GO TO" => map(ccu64, |line| Command::GoTo(line as usize))(i)?, - "LET" => map(variables::parse_var, Command::Var)(i)?, - "REM" => { - let (i, _) = generic::consume_line(i)?; - (i, Command::Comment) - } - _ => (i, Command::None), - }; - - Ok((i, cmd)) -} - -pub fn parse_line(line: &str) -> IResult<&str, Line> { - let (i, line_number) = map(terminated(ccu64, tag(" ")), |l| l as usize)(line)?; - let (i, command) = parse_command(i)?; - Ok((i, (line_number, command))) -} - -pub fn read_program(i: &str) -> IResult<&str, Program> { - let (i, lines) = separated_list0(tag("\n"), parse_line)(i)?; - let mut node = Node::None; - - for line in lines.iter() { - node.push(line.clone()); - } - - Ok((i, Program::new(node))) -} - #[cfg(test)] mod tests { use crate::basic::PrintOutput; - use super::{parse_line, read_program, Command, Line, Node, Primitive}; + use super::{Command, Line, Node, Primitive, Program}; - use crate::parsers::generic::read_string; + use crate::parsers::{commands::parse_line, generic::read_string}; #[test] fn it_parses_a_print_command() { @@ -308,8 +264,8 @@ mod tests { next: Box::new(Node::None), }), }; - let expected = ("", super::Program::new(expected_node)); - let result = read_program(lines).unwrap(); + let expected = Program::new(expected_node); + let result = Program::from(lines); assert_eq!(expected, result); } diff --git a/src/parsers.rs b/src/parsers.rs index bba64a9..0ab2bfb 100644 --- a/src/parsers.rs +++ b/src/parsers.rs @@ -1,2 +1,3 @@ +pub mod commands; pub mod generic; pub mod variables; diff --git a/src/parsers/commands.rs b/src/parsers/commands.rs new file mode 100644 index 0000000..edc9941 --- /dev/null +++ b/src/parsers/commands.rs @@ -0,0 +1,49 @@ +use nom::{ + branch::alt, bytes::complete::tag, character::complete::u64 as ccu64, combinator::map, + sequence::terminated, IResult, +}; + +use crate::basic::{Command, Line, PrintOutput}; + +use super::{generic, variables}; + +pub fn match_command(i: &str) -> IResult<&str, &str> { + alt((tag("PRINT"), tag("GO TO"), tag("LET"), tag("REM")))(i) +} + +pub fn parse_print_command(i: &str) -> IResult<&str, PrintOutput> { + alt(( + map( + alt(( + variables::parse_str_variable_name, + variables::parse_int_variable_name, + )), + PrintOutput::Variable, + ), + map(generic::read_string, PrintOutput::Value), + ))(i) +} + +pub fn parse_command(i: &str) -> IResult<&str, Command> { + let (i, command): (&str, &str) = match_command(i).unwrap_or((i, "")); + let (i, _) = tag(" ")(i)?; + + let (i, cmd) = match command { + "PRINT" => map(parse_print_command, Command::Print)(i)?, + "GO TO" => map(ccu64, |line| Command::GoTo(line as usize))(i)?, + "LET" => map(variables::parse_var, Command::Var)(i)?, + "REM" => { + let (i, _) = generic::consume_line(i)?; + (i, Command::Comment) + } + _ => (i, Command::None), + }; + + Ok((i, cmd)) +} + +pub fn parse_line(line: &str) -> IResult<&str, Line> { + let (i, line_number) = map(terminated(ccu64, tag(" ")), |l| l as usize)(line)?; + let (i, command) = parse_command(i)?; + Ok((i, (line_number, command))) +}