use lexington::{Any,Lexer,Match,Matcher,Scanner,Token,Within};
use lexington::{ShiftReduceParser,ShiftReduceRule};
#[derive(Copy,Clone,Debug,PartialEq)]
enum Kind {
WhiteSpace,
LeftBrace,
RightBrace,
Symbol
}
#[derive(Clone,Debug,PartialEq)]
enum SExp<'a> {
Symbol(&'a str),
List(Vec<SExp<'a>>)
}
fn parse<'a>(input: &'a str) -> Result<SExp,()> {
let whitespace = Any([' ','\n','\t']).one_or_more();
let symbol = Within('0'..='9').or(Within('a'..='z'))
.or(Within('A'..='Z')).or('_').one_or_more();
let scanner = Match(whitespace,Kind::WhiteSpace)
.and_match(symbol,Kind::Symbol)
.and_match('(',Kind::LeftBrace)
.and_match(')',Kind::RightBrace);
let lexer = Lexer::new(input,scanner);
let reduction_rule = |mut l:SExp<'a>,r:SExp<'a>| {
match &mut l {
SExp::List(vs) => { vs.push(r); Ok(l) }
_ => Err(())
}
};
ShiftReduceParser::new()
.apply(reduction_rule)
.terminate(Kind::Symbol,|tok| SExp::Symbol(&input[tok.range()]))
.skip(Kind::WhiteSpace)
.open(Kind::LeftBrace, SExp::List(Vec::new()))
.close(Kind::RightBrace)
.parse(lexer)
}
macro_rules! list{
( $($a:expr),* ) => {
{
let mut v = Vec::new();
$( v.push(SExp::Symbol($a)); )*
SExp::List(v)
}
}
}
#[derive(Debug,PartialEq)]
enum ParseError {
UnexpectedEndOfFile,
UnexpectedToken(Kind)
}
fn check_ok(input: &str, expected: SExp) {
let actual = parse(input).unwrap();
assert_eq!(actual,expected);
}
fn check_err(input: &str, _expecting: ParseError) {
let actual = parse(input).unwrap_err();
assert_eq!(actual,());
}
use SExp::*;
#[test]
fn lisp_01() {
check_ok("x",Symbol("x"));
}
#[test]
fn lisp_02() {
check_ok("901",Symbol("901"));
}
#[test]
fn lisp_03() {
check_ok("0x01",Symbol("0x01"));
}
#[test]
fn lisp_04() {
check_ok("_hello",Symbol("_hello"));
}
#[test]
fn lisp_05() {
check_ok(" xyz",Symbol("xyz"));
}
#[test]
fn lisp_06() {
check_ok("()",list![]);
}
#[test]
fn lisp_07() {
check_ok("(x)",list!["x"]);
}
#[test]
fn lisp_08() {
check_ok("( x)",list!["x"]);
}
#[test]
fn lisp_09() {
check_ok("(x )",list!["x"]);
}
#[test]
fn lisp_10() {
check_ok("(x y)",list!["x","y"]);
}
#[test]
fn lisp_11() {
check_ok("(())",List(vec![List(vec![])]));
}
#[test]
fn lisp_12() {
check_ok("((x))",List(vec![list!["x"]]));
}
#[test]
fn lisp_13() {
check_ok("(x (y))",List(vec![Symbol("x"),List(vec![Symbol("y")])]));
}
#[test]
fn lisp_14() {
check_ok("((x) y)",List(vec![List(vec![Symbol("x")]),Symbol("y")]));
}
#[test]
fn lisp_15() {
check_err("",ParseError::UnexpectedEndOfFile);
}
#[test]
fn lisp_16() {
check_err(" ",ParseError::UnexpectedEndOfFile);
}
#[test]
fn lisp_17() {
check_err("(",ParseError::UnexpectedEndOfFile);
}
#[test]
fn lisp_18() {
check_err("(",ParseError::UnexpectedEndOfFile);
}
#[test]
fn lisp_19() {
check_err("(()",ParseError::UnexpectedEndOfFile);
}
#[test]
fn lisp_20() {
check_err(")",ParseError::UnexpectedToken(Kind::RightBrace));
}