use pasta_dsl::parser::{
parse_str, Arg, BinOp, Expr, FileItem, LocalSceneItem, SetValue, VarScope,
};
fn parse_var_set_expr(rhs: &str) -> Expr {
let src = format!("*scene\n $x={}\n", rhs);
let file = parse_str(&src, "expr_test.pasta").expect("parse should succeed");
let scene = file
.items
.iter()
.find_map(|i| match i {
FileItem::GlobalSceneScope(s) => Some(s),
_ => None,
})
.expect("global scene expected");
let item = scene.local_scenes[0]
.items
.first()
.expect("local scene item expected");
match item {
LocalSceneItem::VarSet(vs) => match &vs.value {
SetValue::Expr(e) => e.clone(),
other => panic!("Expected SetValue::Expr, got {:?}", other),
},
other => panic!("Expected VarSet, got {:?}", other),
}
}
#[test]
fn test_binary_add_halfwidth() {
let expr = parse_var_set_expr("1+2");
match expr {
Expr::Binary { op, lhs, rhs } => {
assert_eq!(op, BinOp::Add);
assert_eq!(*lhs, Expr::Integer(1));
assert_eq!(*rhs, Expr::Integer(2));
}
other => panic!("Expected Binary, got {:?}", other),
}
}
#[test]
fn test_binary_sub() {
let expr = parse_var_set_expr("10-3");
match expr {
Expr::Binary { op, lhs, rhs } => {
assert_eq!(op, BinOp::Sub);
assert_eq!(*lhs, Expr::Integer(10));
assert_eq!(*rhs, Expr::Integer(3));
}
other => panic!("Expected Binary Sub, got {:?}", other),
}
}
#[test]
fn test_binary_div() {
let expr = parse_var_set_expr("10/2");
match expr {
Expr::Binary { op, .. } => assert_eq!(op, BinOp::Div),
other => panic!("Expected Binary Div, got {:?}", other),
}
}
#[test]
fn test_binary_mod() {
let expr = parse_var_set_expr("10%3");
match expr {
Expr::Binary { op, .. } => assert_eq!(op, BinOp::Mod),
other => panic!("Expected Binary Mod, got {:?}", other),
}
}
#[test]
fn test_binary_add_fullwidth_digits_and_operator() {
let expr = parse_var_set_expr("1+2");
match expr {
Expr::Binary { op, lhs, rhs } => {
assert_eq!(op, BinOp::Add);
assert_eq!(*lhs, Expr::Integer(1));
assert_eq!(*rhs, Expr::Integer(2));
}
other => panic!("Expected Binary, got {:?}", other),
}
}
#[test]
fn test_binary_left_associative_chain() {
let expr = parse_var_set_expr("1+2+3");
match expr {
Expr::Binary { op, lhs, rhs } => {
assert_eq!(op, BinOp::Add);
assert_eq!(*rhs, Expr::Integer(3));
match *lhs {
Expr::Binary { op, ref lhs, ref rhs } => {
assert_eq!(op, BinOp::Add);
assert_eq!(**lhs, Expr::Integer(1));
assert_eq!(**rhs, Expr::Integer(2));
}
ref other => panic!("Expected nested Binary lhs, got {:?}", other),
}
}
other => panic!("Expected Binary, got {:?}", other),
}
}
#[test]
fn test_binary_no_operator_precedence() {
let expr = parse_var_set_expr("1+2*3");
match expr {
Expr::Binary { op, lhs, rhs } => {
assert_eq!(op, BinOp::Mul, "outermost op must be Mul (left-assoc)");
assert_eq!(*rhs, Expr::Integer(3));
match *lhs {
Expr::Binary { op, .. } => assert_eq!(op, BinOp::Add),
ref other => panic!("Expected Binary Add lhs, got {:?}", other),
}
}
other => panic!("Expected Binary, got {:?}", other),
}
}
#[test]
fn test_paren_single_term_in_binary() {
let expr = parse_var_set_expr("(5)*3");
match expr {
Expr::Binary { op, lhs, rhs } => {
assert_eq!(op, BinOp::Mul);
assert_eq!(*rhs, Expr::Integer(3));
match *lhs {
Expr::Paren(ref inner) => assert_eq!(**inner, Expr::Integer(5)),
ref other => panic!("Expected Paren lhs, got {:?}", other),
}
}
other => panic!("Expected Binary, got {:?}", other),
}
}
#[test]
fn test_binary_with_local_var_ref_lhs() {
let expr = parse_var_set_expr("$y+1");
match expr {
Expr::Binary { op, lhs, rhs } => {
assert_eq!(op, BinOp::Add);
assert_eq!(*rhs, Expr::Integer(1));
match *lhs {
Expr::VarRef { ref name, ref scope } => {
assert_eq!(name, "y");
assert_eq!(*scope, VarScope::Local);
}
ref other => panic!("Expected VarRef lhs, got {:?}", other),
}
}
other => panic!("Expected Binary, got {:?}", other),
}
}
#[test]
fn test_float_literal_halfwidth() {
let expr = parse_var_set_expr("2.5");
match expr {
Expr::Float(f) => assert!((f - 2.5).abs() < f64::EPSILON),
other => panic!("Expected Float, got {:?}", other),
}
}
#[test]
fn test_float_literal_fullwidth() {
let expr = parse_var_set_expr("2.5");
match expr {
Expr::Float(f) => assert!((f - 2.5).abs() < f64::EPSILON),
other => panic!("Expected Float, got {:?}", other),
}
}
#[test]
fn test_fn_call_keyword_arg() {
let expr = parse_var_set_expr("@fn(key:1)");
match expr {
Expr::FnCall { name, args, .. } => {
assert_eq!(name, "fn");
assert_eq!(args.items.len(), 1);
match &args.items[0] {
Arg::Keyword { key, value } => {
assert_eq!(key, "key");
assert_eq!(*value, Expr::Integer(1));
}
other => panic!("Expected Keyword arg, got {:?}", other),
}
}
other => panic!("Expected FnCall, got {:?}", other),
}
}
#[test]
fn test_fn_call_mixed_positional_and_keyword_args() {
let expr = parse_var_set_expr("@fn(1、key:2)");
match expr {
Expr::FnCall { name, args, .. } => {
assert_eq!(name, "fn");
assert_eq!(args.items.len(), 2);
match &args.items[0] {
Arg::Positional(e) => assert_eq!(*e, Expr::Integer(1)),
other => panic!("Expected Positional first arg, got {:?}", other),
}
match &args.items[1] {
Arg::Keyword { key, value } => {
assert_eq!(key, "key");
assert_eq!(*value, Expr::Integer(2));
}
other => panic!("Expected Keyword second arg, got {:?}", other),
}
}
other => panic!("Expected FnCall, got {:?}", other),
}
}
#[test]
fn test_fn_call_binary_expr_in_positional_arg() {
let expr = parse_var_set_expr("@fn(1+2)");
match expr {
Expr::FnCall { args, .. } => {
assert_eq!(args.items.len(), 1);
match &args.items[0] {
Arg::Positional(Expr::Binary { op, lhs, rhs }) => {
assert_eq!(*op, BinOp::Add);
assert_eq!(**lhs, Expr::Integer(1));
assert_eq!(**rhs, Expr::Integer(2));
}
other => panic!("Expected Positional Binary arg, got {:?}", other),
}
}
other => panic!("Expected FnCall, got {:?}", other),
}
}