serc-cli 0.1.1

An experimental CPython bytecode compiler, written in Rust.
mod common;

use serc::{CompileOptions, PythonVersion};

#[test]
fn nested_comprehension_yields_match_python() {
    let sources = [
        "def f():\n    return [(yield (yield x)) for x in xs]\n",
        "def f():\n    return [(yield from (yield x)) for x in xs]\n",
        "def f():\n    return [(yield (yield from x)) for x in xs]\n",
        "def f():\n    return [(yield from (yield from x)) for x in xs]\n",
        "def f():\n    return [(yield ((yield a), (yield b))) for x in xs]\n",
        "def f():\n    return [(yield (yield (yield z))) for x in xs]\n",
        "def f():\n    return {(yield (yield x)) for x in xs}\n",
        "def f():\n    return {x: (yield (yield x)) for x in xs}\n",
        "def f():\n    return ((yield (yield x)) for x in xs)\n",
        "def f():\n    return [(yield (lambda: (yield x))) for x in xs]\n",
        "def f():\n    return [(yield [y for y in (yield x)]) for x in xs]\n",
        "def f():\n    return [(yield {(yield y) for y in ys}) for x in xs]\n",
        "def f():\n    return [(yield {(yield k):(yield v) for k in ks}) for x in xs]\n",
        "def f():\n    return [(yield {(k := 1): (yield v) for k in ks}) for x in xs]\n",
        "def f():\n    return [(yield {(yield k): (k := 1) for k in ks}) for x in xs]\n",
        "class C:\n    result = [(yield {(x := 1): 0 for x in xs}) for z in zs]\n",
        "class C:\n    result = [(yield [[(b := 1) for c in cs] for b in bs]) for a in aa]\n",
        "class C:\n    result = [(yield [(q := 1) for y in ys]) for x in xs]\n",
        "def f():\n    return [(yield {0: (yield a), (yield b): 0}) for x in xs]\n",
        "def f():\n    return [(yield {(yield a): 0, 1: (yield b)}) for x in xs]\n",
        "def f():\n    return [(yield (lambda a=(yield x), a=1: 0)) for x in xs]\n",
        "def f():\n    return [(yield ((lambda a,a: 0), (yield x))) for x in xs]\n",
        "def f():\n    return [(yield [y for y in (lambda: (w := 1))]) for x in xs]\n",
        "def f():\n    return [(yield [y for y in (lambda p=(w := 1): p)]) for x in xs]\n",
        "def f():\n    return [x for x in xs if (yield (yield x))]\n",
        "def f():\n    return [y for x in xs for y in (yield (yield x))]\n",
        "def f():\n    return [(yield ((await x), (yield y))) for x in xs]\n",
        "def f():\n    return [(yield (lambda: (await x))) for x in xs]\n",
        "def f():\n    return [(yield (lambda x=(await a): x)) for x in xs]\n",
        "def f():\n    return [(yield ((lambda: (await x)), (yield y))) for x in xs]\n",
        "def f():\n    return ((yield (lambda: (await x))) for x in xs)\n",
        "def f():\n    return ((yield (lambda x=(await a): x)) for x in xs)\n",
        "def f():\n    return [(yield *x) for x in xs]\n",
        "def f():\n    return [(yield *(yield x)) for x in xs]\n",
        "def f():\n    return [(yield ((g(a=1,a=2)), (yield x))) for x in xs]\n",
        "def f():\n    return [(yield ((__debug__ := 1), (yield x))) for x in xs]\n",
        "def f():\n    return [(yield ((yield x), (__debug__ := 1))) for x in xs]\n",
        "def f():\n    return [(yield (__debug__ := (yield x))) for x in xs]\n",
        "def f():\n    return [(yield (__debug__ := 1)) for x in xs]\n",
        "def f():\n    return [(yield (yield μ)) for x in xs]\n",
        "async def f():\n    value = [(yield from (yield x)) for x in xs]\n",
    ];
    let nested = (0..40).fold(
        "{(k := 1): (yield v) for k in ks}".to_owned(),
        |expression, _| format!("[(yield {expression}) for x in xs]"),
    );
    let deep_source = format!("def f():\n    return {nested}\n");
    for version in common::PYTHON_VERSIONS {
        let options = CompileOptions {
            python_version: version,
            ..CompileOptions::default()
        };
        let modern_debug_after_star =
            matches!(version, PythonVersion::Py314 | PythonVersion::Py315)
                .then_some("*first\n[(yield (__debug__ := 1)) for x in xs]\n");
        for source in sources
            .into_iter()
            .chain(modern_debug_after_star)
            .chain(std::iter::once(deep_source.as_str()))
        {
            let diagnostic = common::diagnostics::syntax_diagnostic_with_bytes(version, source);
            let expected = diagnostic.byte_range(source);
            diagnostic.assert_syntax_error(source, &options, expected);
        }
    }
}