use lexington::{Any,Lexer,Match,Matcher,Scanner,Token,Within}; use lexington::{ShiftReduceParser,ShiftReduceRule}; /// A minimal kind of token for testing. #[derive(Clone,Copy,PartialEq)] enum Kind { WhiteSpace, Number, LeftBrace, RightBrace } #[test] fn shift_reduce_parser_01() { check("1", Ok(vec![1])); } #[test] fn shift_reduce_parser_02() { check("x", Err(())); } #[test] fn shift_reduce_parser_03() { check("(1)", Ok(vec![1])); } #[test] fn shift_reduce_parser_04() { check("((1))", Ok(vec![1])); } #[test] fn shift_reduce_parser_05() { check("(1 2)", Ok(vec![1,2])); } #[test] fn shift_reduce_parser_06() { check("(1 2 3)", Ok(vec![1,2,3])); } #[test] fn shift_reduce_parser_07() { check("((1) 2 3)", Ok(vec![1,2,3])); } #[test] fn shift_reduce_parser_08() { check("((1 2) 3)", Ok(vec![1,2,3])); } #[test] fn shift_reduce_parser_09() { check("(((1) 2) 3)", Ok(vec![1,2,3])); } #[test] fn shift_reduce_parser_10() { check("((1 2 3))", Ok(vec![1,2,3])); } #[test] fn shift_reduce_parser_11() { check("(1 (2 3))", Ok(vec![1,2,3])); } #[test] fn shift_reduce_parser_12() { check("(1 (2 (3)))", Ok(vec![1,2,3])); } #[test] fn shift_reduce_parser_13() { check("(1 (2) 3)", Ok(vec![1,2,3])); } #[test] fn shift_reduce_parser_14() { check("(1 2 (3))", Ok(vec![1,2,3])); } fn check(input: &str, expected: Result,()>) { let tokens = lex(input); // Simple reduction rule for combining vectors let reduction_rule = |mut l:Vec,r:Vec| { l.extend(r); Ok(l) }; // Rule for parsing strings into numbers let actual = ShiftReduceParser::new() .apply(reduction_rule) .terminate(Kind::Number,|tok| vec![input[tok.range()].parse().unwrap()]) .skip(Kind::WhiteSpace) .open(Kind::LeftBrace, Vec::new()) .close(Kind::RightBrace) .parse(tokens); // Check input matches output assert_eq!(actual,expected); } // ======================================================================== // Helpers // ======================================================================== /// Construct a very simple lexer for S-expressions, and scan them to /// produce a list of zero or more tokens. fn lex(input: &str) -> Vec> { // [ \n\t]+ let whitespace = Any([' ','\n','\t']).one_or_more(); // [0..9]+ let number = Within('0'..='9').one_or_more(); // Construct scanner let scanner = Match(whitespace,Kind::WhiteSpace) .and_match(number,Kind::Number) .and_match('(',Kind::LeftBrace) .and_match(')',Kind::RightBrace); // Construct the lexer. Lexer::new(input,scanner).collect() }