use l1_ir::ast::{Value,Expression,Program,LIPart,TIPart,FunctionDefinition,LHSPart};
use l1_ir::eval::{eval};

#[test]
fn eval_empty() {
   assert_eq!(
      eval(Program::<()>::program(vec![],vec![])).unwrap(),
      Value::tuple(vec![])
   );
}

#[test]
fn eval_failure() {
   assert!(
      eval(Program::program(
         vec![],
         vec![Expression::failure(())]
      )).is_err()
   );
}

#[test]
fn eval_li() {
   assert_eq!(
      eval(Program::program(
         vec![],
         vec![Expression::literal("",())],
      )).unwrap(),
      Value::literal("")
   );
   assert_eq!(
      eval(Program::program(
         vec![],
         vec![Expression::li(vec![
            LIPart::literal("a")
         ],())],
      )).unwrap(),
      Value::literal("a")
   );
   assert_eq!(
      eval(Program::program(
         vec![],
         vec![Expression::li(vec![
            LIPart::literal("a"),
            LIPart::literal("bc"),
         ],())],
      )).unwrap(),
      Value::literal("abc")
   );
}

#[test]
fn eval_ti() {
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![],
         vec![Expression::ti(vec![],())],
      )).unwrap()),
      "()"
   );
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![],
         vec![Expression::ti(vec![
            TIPart::tuple(vec![
               Value::literal("a"),
            ])
         ],())],
      )).unwrap()),
      r#"("a",)"#
   );
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![],
         vec![Expression::ti(vec![
            TIPart::tuple(vec![
               Value::literal("a"),
               Value::literal("bc"),
            ])
         ],())],
      )).unwrap()),
      r#"("a","bc")"#
   );
}

#[test]
fn eval_function() {
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![FunctionDefinition::define(
            vec![],
            vec![Expression::ti(vec![
               TIPart::tuple(vec![
                  Value::literal("a"),
                  Value::literal("bc"),
               ])
            ],())]
         )],
         vec![],
      )).unwrap()),
      "()"
   );
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![FunctionDefinition::define(
            vec![],
            vec![],
         )],
         vec![
            Expression::apply(0,vec![],()),
         ],
      )).unwrap()),
      r#"()"#
   );
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![FunctionDefinition::define(
            vec![],
            vec![Expression::ti(vec![
               TIPart::tuple(vec![
                  Value::literal("a"),
                  Value::literal("bc"),
               ])
            ],())]
         )],
         vec![
            Expression::apply(0,vec![],()),
         ],
      )).unwrap()),
      r#"("a","bc")"#
   );
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![FunctionDefinition::define(
            vec![24],
            vec![Expression::ti(vec![
               TIPart::tuple(vec![
                  Value::literal("a"),
               ]),
               TIPart::variable(24),
            ],())]
         )],
         vec![
            Expression::apply(0,vec![
               Expression::li(vec![
                  LIPart::literal("b"),
                  LIPart::literal("cd"),
               ],())
            ],()),
         ],
      )).unwrap()),
      r#"("a","bcd")"#
   );
}

#[test]
fn eval_pattern() {
   assert!(
      eval(Program::program(
         vec![],
         vec![Expression::pattern(
            Expression::li(vec![
               LIPart::literal("b"),
               LIPart::literal("cd"),
            ],()),
            vec![],
         ())],
      )).is_err(),
   );
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![],
         vec![Expression::pattern(
            Expression::li(vec![
               LIPart::literal("b"),
               LIPart::literal("cd"),
            ],()),
            vec![(
               LHSPart::any(),
               Expression::literal("c",())
            )],
         ())],
      )).unwrap()),
      r#""c""#
   );
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![],
         vec![Expression::pattern(
            Expression::li(vec![
               LIPart::literal("b"),
               LIPart::literal("cd"),
            ],()),
            vec![(
               LHSPart::literal("bcd"),
               Expression::literal("e",())
            )],
         ())],
      )).unwrap()),
      r#""e""#
   );
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![],
         vec![Expression::pattern(
            Expression::li(vec![
               LIPart::literal("b"),
               LIPart::literal("cd"),
            ],()),
            vec![(
               LHSPart::variable(123),
               Expression::variable(123,())
            )],
         ())],
      )).unwrap()),
      r#""bcd""#
   );
   assert_eq!(
      format!("{:?}",eval(Program::program(
         vec![],
         vec![Expression::pattern(
            Expression::tuple(vec![
               Value::literal("mno"),
            ],()),
            vec![(
               LHSPart::tuple(vec![
                  LHSPart::variable(123)
               ]),
               Expression::variable(123,())
            )],
         ())],
      )).unwrap()),
      r#""mno""#
   );
}
