openpql-runner 0.1.3

A high-performance Rust implementation of Poker Query Language (PQL), enabling SQL-like queries for poker analysis and calculations. This project is a spiritual successor to the original Java implementation developed by Odds Oracle.
Documentation
use super::*;

fn resolve_range<'vm, T>(
    game: PQLGame,
    string: &'vm ast::Str,
) -> PQLResult<VmHeapValue>
where
    T: TryFrom<(PQLGame, &'vm str)>,
    VmHeapValue: From<T>,
    PQLErrorKind: From<<T as TryFrom<(PQLGame, &'vm str)>>::Error>,
{
    match T::try_from((game, string.inner)) {
        Ok(range) => Ok(range.into()),
        Err(err) => Err(mk_err(string, err)),
    }
}

pub fn push_str(
    data: &mut CompilerData,
    string: &ast::Str,
    expected_type: PQLType,
) -> PQLResult<PQLType> {
    let (value, rtn_type) = match expected_type {
        PQLType::RANGE => (
            resolve_range::<PQLRange>(data.static_data.game, string)?,
            PQLType::RANGE,
        ),
        PQLType::BOARDRANGE => (
            resolve_range::<PQLBoardRange>(data.static_data.game, string)?,
            PQLType::BOARDRANGE,
        ),
        _ => (string.inner.to_string().into(), PQLType::STRING),
    };

    let idx = data.heap.len();
    data.heap.push(value);

    data.prog
        .push((VmInstruction::Push(idx.into()), string.loc));

    Ok(rtn_type)
}

#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
    use super::*;
    use crate::*;

    fn assert_str(
        type_hint: PQLType,
        src: &str,
        expected: VmHeapValue,
        expected_type: PQLType,
    ) {
        let expr = parse_str(src).unwrap();

        let mut data = CompilerData::default();

        let tp = push_str(&mut data, &expr, type_hint).unwrap();

        assert_eq!(data.prog[0].0, VmInstruction::Push(sval!(@ref 0)));
        assert!(data.heap[0].is_eq(&expected));
        assert_eq!(tp, expected_type);
    }

    #[test]
    fn test_str() {
        assert_str(
            PQLType::all(),
            "'str'",
            VmHeapValue::Str("str".to_string()),
            PQLType::STRING,
        );

        assert_str(
            PQLType::STRING,
            "'str'",
            VmHeapValue::Str("str".to_string()),
            PQLType::STRING,
        );
    }

    #[test]
    fn test_range() {
        assert_str(
            PQLType::RANGE,
            "'AA'",
            VmHeapValue::Range((PQLGame::default(), "AA").try_into().unwrap()),
            PQLType::RANGE,
        );
    }

    #[test]
    fn test_board_range() {
        assert_str(
            PQLType::BOARDRANGE,
            "'AA'",
            VmHeapValue::BoardRange(
                (PQLGame::default(), "AA").try_into().unwrap(),
            ),
            PQLType::BOARDRANGE,
        );
    }

    fn assert_err<E>(expected_type: PQLType, src: &str, err: E)
    where
        PQLErrorKind: From<E>,
    {
        let expr = parse_str(src).unwrap();

        let mut data = CompilerData::default();

        assert_eq!(
            push_str(&mut data, &expr, expected_type),
            Err(mk_err(&expr, err))
        );
    }

    #[test]
    fn test_str_err() {
        assert_err(PQLType::RANGE, "'[N]'", RangeError::InvalidList((0, 3)));
        assert_err(
            PQLType::BOARDRANGE,
            "'[N]'",
            RangeError::InvalidList((0, 3)),
        );
    }
}