#!/usr/bin/env python3
# ==============================================================================
#  std_probe.py — 快速演示「同一段代码在不同语言标准下的支持情况」
#
#  用途（对应任务 1）：把一段 C 或 C++ 代码片段，在多个 -std= 下逐个编译，报告
#  pass / fail / warnings，从而直观看到「某概念在哪个版本成立」。
#
#  用法：
#    tools/std_probe.py --lang c   --code 'int main(){ __auto_type x=1; return x; }'
#    tools/std_probe.py --lang c++ --file snippet.cpp
#    tools/std_probe.py --lang c   --file snippet.c --standards c89,c99,c11,c17,c23
#
#  说明：
#    * 编译器用宿主机 gcc/g++（本仓库 gcc 13 原生支持全部目标标准）。
#    * 仅做语法编译（-fsyntax-only），不链接、不运行，避免副作用。
#    * 退出码：全 pass 为 0；任一 fail 为 1（便于脚本/CI 判定）。
# ------------------------------------------------------------------------------
import argparse, os, subprocess, sys, tempfile

# 默认要探测的标准列表（C 与 C++ 各一组，覆盖课程相关版本）
DEFAULTS = {
    "c":   ["c89", "c99", "c11", "c17", "c23"],
    "c++": ["c++98", "c++03", "c++11", "c++14", "c++17", "c++20", "c++23"],
}

def probe(code: str, lang: str, standards, extra_flags=None):
    """Compile `code` under each standard in `standards` (syntax-only). Returns
    list of dicts: {std, ok, warnings, errors}."""
    compiler = "gcc" if lang == "c" else "g++"
    results = []
    extra_flags = extra_flags or []
    with tempfile.NamedTemporaryFile("w", suffix=(".c" if lang == "c" else ".cpp"),
                                     delete=False) as f:
        f.write(code)
        src = f.name
    try:
        for std in standards:
            cmd = [compiler, f"-std={std}", "-fsyntax-only", "-Wall", "-Wextra"] + extra_flags + [src]
            p = subprocess.run(cmd, capture_output=True, text=True)
            combined = (p.stderr or "") + (p.stdout or "")
            # categorize lines: gcc/clang warnings vs errors
            warns = [l for l in combined.splitlines() if "warning:" in l]
            errs = [l for l in combined.splitlines() if "error:" in l]
            results.append({
                "std": std,
                "ok": p.returncode == 0,
                "warnings": warns,
                "errors": errs,
            })
    finally:
        os.unlink(src)
    return results

def main():
    ap = argparse.ArgumentParser(description="Probe a C/C++ snippet across -std= versions.")
    g = ap.add_mutually_exclusive_group(required=True)
    g.add_argument("--code", help="inline code snippet")
    g.add_argument("--file", help="path to a source file")
    ap.add_argument("--lang", choices=["c", "c++"], required=True,
                    help="language (selects compiler & default standards)")
    ap.add_argument("--standards", default=None,
                    help="comma-separated -std values (default: course-relevant set)")
    ap.add_argument("--show-warnings", action="store_true",
                    help="print warning lines (default: only summarize)")
    ap.add_argument("--pedantic-errors", action="store_true",
                    help="add -pedantic-errors so removed/deprecated features FAIL hard "
                         "(gcc otherwise lets many removed features compile as warnings)")
    args = ap.parse_args()

    code = args.code if args.code else open(args.file).read()
    standards = args.standards.split(",") if args.standards else DEFAULTS[args.lang]
    extra_flags = ["-pedantic-errors"] if args.pedantic_errors else []

    print(f"Compiler : {('gcc' if args.lang=='c' else 'g++')} ({subprocess.run(['gcc','--version'],capture_output=True,text=True).stdout.splitlines()[0]})")
    print(f"Language : {args.lang}")
    print(f"Standards: {', '.join(standards)}"
          + ("   [pedantic-errors ON]" if args.pedantic_errors else ""))
    print("-" * 64)

    results = probe(code, args.lang, standards, extra_flags=extra_flags)
    any_fail = False
    for r in results:
        flag = "PASS" if r["ok"] else "FAIL"
        w = f"  {len(r['warnings'])} warning(s)" if r["warnings"] else ""
        e = f"  {len(r['errors'])} error(s)" if r["errors"] else ""
        print(f"  -std={r['std']:<8} : {flag}{w}{e}")
        if not r["ok"]:
            any_fail = True
            for line in r["errors"][:3]:
                print(f"        {line.strip()}")
        if args.show_warnings:
            for line in r["warnings"][:3]:
                print(f"        (warn) {line.strip()}")
    print("-" * 64)
    print("Result   : " + ("ALL PASS" if not any_fail else "SOME FAIL"))
    return 1 if any_fail else 0

if __name__ == "__main__":
    sys.exit(main())
