From 81b7b70a4763ab7b4ce800ab738056ee90b14daa Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy <mmstickman@gmail.com> Date: Sun, 30 Jul 2017 02:55:44 -0400 Subject: [PATCH] Reduce Dependency On PEG --- examples/conditionals.ion | 9 ++++ examples/conditionals.out | 9 ++++ src/parser/grammar.rustpeg | 68 +++-------------------- src/parser/peg.rs | 108 +++++++++++++++++++++++++++---------- 4 files changed, 105 insertions(+), 89 deletions(-) diff --git a/examples/conditionals.ion b/examples/conditionals.ion index 46c1b24b..e8674142 100644 --- a/examples/conditionals.ion +++ b/examples/conditionals.ion @@ -7,3 +7,12 @@ false && echo cant get here false || false || echo double or true && true && echo double and false || true && echo or and +contains "one two three" two && echo true || echo false +contains "one two three" abc two && echo true || echo false +contains "one two three" foo bar && echo true || echo false +starts-with "one two three" one && echo true || echo false +starts-with "one two three" abc one && echo true || echo false +starts-with "one two three" three && echo true || echo false +ends-with "one two three" three && echo true || echo false +ends-with "one two three" abc three && echo true || echo false +ends-with "one two three" one two && echo true || echo false diff --git a/examples/conditionals.out b/examples/conditionals.out index 1bb8764d..41c844c6 100644 --- a/examples/conditionals.out +++ b/examples/conditionals.out @@ -5,3 +5,12 @@ true double or double and or and +true +true +false +true +true +false +true +true +false diff --git a/src/parser/grammar.rustpeg b/src/parser/grammar.rustpeg index ac86c196..2ceded8c 100644 --- a/src/parser/grammar.rustpeg +++ b/src/parser/grammar.rustpeg @@ -1,75 +1,19 @@ -use parser::assignments::parse_assignment; use parser::{pipelines, ArgumentSplitter}; use parser::peg::get_function_args; use shell::flow_control::*; #[pub] parse_ -> Statement - = let_ - / export_ - / if_ - / else_if_ - / else_ - / for_ + = for_ / while_ / fn_ - / break_ - / continue_ / match_ / case_ / pipelines -#[pub] -let_ -> Statement - = whitespace* "let" whitespace+ value:$(.*) { - Statement::Let { expression: parse_assignment(value) } - } - -#[pub] -export_ -> Statement - = whitespace* "export" whitespace+ value:$(.*) { - Statement::Export(parse_assignment(value)) - } - -#[pub] -break_ -> Statement - = whitespace* "break" { Statement::Break } - -#[pub] -continue_ -> Statement - = whitespace* "continue" { Statement::Continue } - -#[pub] -if_ -> Statement - = whitespace* "if" whitespace+ command:$(.*) {? - pipelines::Collector::run(command).map(|p| { - Statement::If { - expression: p, - success: Vec::new(), - else_if: Vec::new(), - failure: Vec::new() - } - }) - } - -#[pub] -else_if_ -> Statement - = whitespace* "else" whitespace+ "if" whitespace+ command:$(.*) {? - pipelines::Collector::run(command).map(|p| { - Statement::ElseIf(ElseIf { - expression: p, - success: Vec::new(), - }) - }) - } - -#[pub] -else_ -> Statement - = whitespace* "else" whitespace* { Statement::Else } - #[pub] fn_ -> Statement - = whitespace* "fn " n:_name whitespace* args:_fn_args whitespace* description:_description? {? + = "fn " n:_name whitespace* args:_fn_args whitespace* description:_description? {? get_function_args(args).map(|args| Statement::Function { description: description.unwrap_or("".into()), name: n.into(), @@ -98,7 +42,7 @@ _fn_arg -> String #[pub] for_ -> Statement - = whitespace* "for" whitespace+ n:_name whitespace+ "in" whitespace+ expr:$(.*) { + = "for" whitespace+ n:_name whitespace+ "in" whitespace+ expr:$(.*) { Statement::For { variable: n.into(), values: ArgumentSplitter::new(expr).map(String::from).collect(), @@ -112,12 +56,12 @@ value_ -> Option<String> = contents:$(.*) { Some(contents.into())} pattern_ -> Option<String> = wildcard_ / value_ case_ -> Statement - = whitespace* "case" whitespace+ p:pattern_ { + = "case" whitespace+ p:pattern_ { Statement::Case(Case { value: p, statements: Vec::new() }) } #[pub] -match_ -> Statement = whitespace* "match" whitespace+ expression:$(.*) { +match_ -> Statement = "match" whitespace+ expression:$(.*) { Statement::Match { expression: expression.into(), cases: Vec::new() @@ -126,7 +70,7 @@ match_ -> Statement = whitespace* "match" whitespace+ expression:$(.*) { #[pub] while_ -> Statement - = whitespace* "while" whitespace+ command:$(.*) {? + = "while" whitespace+ command:$(.*) {? pipelines::Collector::run(command).map(|p| { Statement::While { expression: p, diff --git a/src/parser/peg.rs b/src/parser/peg.rs index 014720c5..52fe7a91 100644 --- a/src/parser/peg.rs +++ b/src/parser/peg.rs @@ -1,12 +1,14 @@ use std::io::{stderr, Write}; use std::fmt; -use shell::flow_control::{Statement, FunctionArgument, Type}; +use shell::flow_control::{ElseIf, Statement, FunctionArgument, Type}; use self::grammar::parse_; use shell::directory_stack::DirectoryStack; use shell::{JobKind, Job}; use shell::variables::Variables; -use parser::{expand_string, ExpanderFunctions, Select}; +use super::{expand_string, ExpanderFunctions, Select}; +use super::assignments::parse_assignment; +use super::pipelines; #[derive(Debug, PartialEq, Clone, Copy)] pub enum RedirectFrom { Stdout, Stderr, Both} @@ -112,8 +114,67 @@ impl fmt::Display for Pipeline { } pub fn parse(code: &str) -> Statement { - let trimmed = code.trim(); - if trimmed == "end" { return Statement::End; } + let mut trimmed = code.trim(); + match trimmed { + "end" => return Statement::End, + "break" => return Statement::Break, + "continue" => return Statement::Continue, + _ if trimmed.starts_with("let ") => { + trimmed = trimmed[4..].trim_left(); + return Statement::Let { expression: parse_assignment(trimmed) } + }, + _ if trimmed.starts_with("export ") => { + trimmed = trimmed[7..].trim_left(); + return Statement::Export(parse_assignment(trimmed)) + }, + _ if trimmed.starts_with("if ") => { + trimmed = trimmed[3..].trim_left(); + + let result = pipelines::Collector::run(trimmed).map(|p| { + Statement::If { + expression: p, + success: Vec::new(), + else_if: Vec::new(), + failure: Vec::new() + } + }); + + match result { + Ok(statement) => return statement, + Err(err) => { + let stderr = stderr(); + let _ = writeln!(stderr.lock(), "ion: Syntax {}", err); + return Statement::Default + } + } + } + "else" => return Statement::Else, + _ if trimmed.starts_with("else") => { + let mut trimmed = trimmed[4..].trim_left(); + if trimmed.len() == 0 { + return Statement::Else + } else if trimmed.starts_with("if ") { + trimmed = trimmed[3..].trim_left(); + let result = pipelines::Collector::run(&trimmed).map(|p| { + Statement::ElseIf(ElseIf { + expression: p, + success: Vec::new(), + }) + }); + + match result { + Ok(statement) => return statement, + Err(err) => { + let stderr = stderr(); + let _ = writeln!(stderr.lock(), "ion: Syntax {}", err); + return Statement::Default + } + } + } + } + _ => () + } + match parse_(trimmed) { Ok(code_ok) => code_ok, Err(err) => { @@ -228,7 +289,7 @@ else #[test] fn parsing_ifs() { // Default case where spaced normally - let parsed_if = if_("if test 1 -eq 2").unwrap(); + let parsed_if = parse("if test 1 -eq 2"); let correct_parse = Statement::If { expression: Pipeline::new( vec!(Job::new( @@ -246,42 +307,40 @@ else assert_eq!(correct_parse, parsed_if); // Trailing spaces after final value - let parsed_if = if_("if test 1 -eq 2 ").unwrap(); + let parsed_if = parse("if test 1 -eq 2 "); assert_eq!(correct_parse, parsed_if); } #[test] fn parsing_elses() { // Default case where spaced normally - let parsed_if = else_("else").unwrap(); + let mut parsed_if = parse("else"); let correct_parse = Statement::Else; assert_eq!(correct_parse, parsed_if); // Trailing spaces after final value - let parsed_if = else_("else ").unwrap(); - let correct_parse = Statement::Else; + parsed_if = parse("else "); assert_eq!(correct_parse, parsed_if); // Leading spaces after final value - let parsed_if = else_(" else").unwrap(); - let correct_parse = Statement::Else; + parsed_if = parse(" else"); assert_eq!(correct_parse, parsed_if); } #[test] fn parsing_ends() { // Default case where spaced normally - let parsed_if = end_("end").unwrap(); + let parsed_if = parse("end"); let correct_parse = Statement::End; assert_eq!(correct_parse, parsed_if); // Trailing spaces after final value - let parsed_if = end_("end ").unwrap(); + let parsed_if = parse("end "); let correct_parse = Statement::End; assert_eq!(correct_parse, parsed_if); // Leading spaces after final value - let parsed_if = end_(" end").unwrap(); + let parsed_if = parse(" end"); let correct_parse = Statement::End; assert_eq!(correct_parse, parsed_if); } @@ -289,7 +348,7 @@ else #[test] fn parsing_functions() { // Default case where spaced normally - let parsed_if = fn_("fn bob").unwrap(); + let parsed_if = parse("fn bob"); let correct_parse = Statement::Function{ description: "".into(), name: "bob".into(), @@ -299,15 +358,14 @@ else assert_eq!(correct_parse, parsed_if); // Trailing spaces after final value - let parsed_if = fn_("fn bob ").unwrap(); + let parsed_if = parse("fn bob "); assert_eq!(correct_parse, parsed_if); // Leading spaces after final value - let parsed_if = fn_(" fn bob").unwrap(); - assert_eq!(correct_parse, parsed_if); + let parsed_if = parse(" fn bob"); // Default case where spaced normally - let parsed_if = fn_("fn bob a b").unwrap(); + let parsed_if = parse("fn bob a b"); let correct_parse = Statement::Function{ description: "".into(), name: "bob".into(), @@ -317,14 +375,10 @@ else assert_eq!(correct_parse, parsed_if); // Trailing spaces after final value - let parsed_if = fn_("fn bob a b ").unwrap(); - assert_eq!(correct_parse, parsed_if); - - // Leading spaces after final value - let parsed_if = fn_(" fn bob a b").unwrap(); + let parsed_if = parse("fn bob a b "); assert_eq!(correct_parse, parsed_if); - let parsed_if = fn_("fn bob a b --bob is a nice function").unwrap(); + let parsed_if = parse("fn bob a b --bob is a nice function"); let correct_parse = Statement::Function{ description: "bob is a nice function".to_string(), name: "bob".into(), @@ -332,9 +386,9 @@ else statements: vec!() }; assert_eq!(correct_parse, parsed_if); - let parsed_if = fn_("fn bob a b -- bob is a nice function").unwrap(); + let parsed_if = parse("fn bob a b -- bob is a nice function"); assert_eq!(correct_parse, parsed_if); - let parsed_if = fn_("fn bob a b --bob is a nice function").unwrap(); + let parsed_if = parse("fn bob a b --bob is a nice function"); assert_eq!(correct_parse, parsed_if); } } -- GitLab