use std::path::{Path, PathBuf};
use pasta_dsl::parser::parse_str;
use pasta_lua::LuaTranspiler;
use pasta_lua::debug::source_map::canonicalize_chunk_name;
use pasta_lua::loader::{CacheManager, PastaLoader};
fn transpile_fixture(file: &Path) -> String {
let pasta = parse_str(FIXTURE, &file.to_string_lossy()).expect("fixture must parse");
let transpiler = LuaTranspiler::default();
let mut out = Vec::new();
transpiler
.transpile(&pasta, &mut out)
.expect("fixture must transpile");
String::from_utf8(out).expect("generated lua is valid utf-8")
}
const FIXTURE: &str = include_str!("../fixtures/debug_break_coalesce.pasta");
const MULTI_TO_ONE_MARKER: &str = "合計は@加算ループ()";
const LOOP_BODY_MARKER: &str = "total = total + i";
fn unique_line_of(needle: &str) -> u32 {
let hits: Vec<u32> = FIXTURE
.lines()
.enumerate()
.filter(|(_, l)| {
let t = l.trim_start();
!t.starts_with('#') && !t.starts_with('#') && l.contains(needle)
})
.map(|(i, _)| i as u32 + 1)
.collect();
assert_eq!(
hits.len(),
1,
"fixture invariant: marker {needle:?} must appear on exactly one line, got {hits:?}"
);
hits[0]
}
fn write_fixture(base_dir: &Path) -> PathBuf {
let path = base_dir.join("dic/test/debug_break_coalesce.pasta");
std::fs::create_dir_all(path.parent().unwrap()).expect("mkdir dic");
std::fs::write(&path, FIXTURE).expect("write fixture .pasta");
path
}
#[test]
fn fixture_target_pasta_line_maps_to_multiple_lua_lines() {
let temp = tempfile::TempDir::new().expect("temp dir");
let base_dir = temp.path().to_path_buf();
let file = write_fixture(&base_dir);
let cache_manager = CacheManager::new(base_dir.clone(), "profile/pasta/cache/lua");
let source_map = PastaLoader::build_source_map(std::slice::from_ref(&file), &cache_manager, false);
let chunk = cache_manager
.source_to_cache_path(&file)
.to_string_lossy()
.to_string();
let file_key = file.to_string_lossy().to_string();
let target_line = unique_line_of(MULTI_TO_ONE_MARKER);
let lua_coords = source_map.resolve_pasta_to_lua(&file_key, target_line);
assert!(
lua_coords.len() >= 2,
"6.2(a): 対象 `.pasta` 行 {target_line} は ≥2 の `.lua` 行へ展開されること \
(multi-to-one), got {lua_coords:?}"
);
for (mapped_chunk, lua_line) in &lua_coords {
assert_eq!(
canonicalize_chunk_name(mapped_chunk),
canonicalize_chunk_name(&chunk),
"逆引き結果は当該チャンクを指す"
);
let back = source_map
.resolve_lua_to_pasta(&chunk, *lua_line)
.expect("前方解決できること");
assert_eq!(
back.line, target_line,
"6.2(a): `.lua` 行 {lua_line} は対象 `.pasta` 行 {target_line} へ等価解決する \
(多対1の各 `.lua` 行が同一 `.pasta` 行を指す)"
);
}
}
#[test]
fn fixture_loop_revisits_the_same_pasta_line() {
let temp = tempfile::TempDir::new().expect("temp dir");
let base_dir = temp.path().to_path_buf();
let file = write_fixture(&base_dir);
let cache_manager = CacheManager::new(base_dir.clone(), "profile/pasta/cache/lua");
let source_map = PastaLoader::build_source_map(std::slice::from_ref(&file), &cache_manager, false);
let chunk = cache_manager
.source_to_cache_path(&file)
.to_string_lossy()
.to_string();
let file_key = file.to_string_lossy().to_string();
let loop_line = unique_line_of(LOOP_BODY_MARKER);
let loop_coords = source_map.resolve_pasta_to_lua(&file_key, loop_line);
assert_eq!(
loop_coords.len(),
1,
"6.2(b): ループ本体 `.pasta` 行 {loop_line} は単一の `.lua` 座標を持つ \
(ループ反復で同一行を再訪する),got {loop_coords:?}"
);
let (loop_chunk, loop_lua_line) = &loop_coords[0];
assert_eq!(
canonicalize_chunk_name(loop_chunk),
canonicalize_chunk_name(&chunk),
"ループ本体の逆引きは当該チャンクを指す"
);
let generated_lua = transpile_fixture(&file);
let lines: Vec<&str> = generated_lua.lines().collect();
let body_idx = (*loop_lua_line as usize)
.checked_sub(1)
.expect("1-origin lua line");
assert!(
body_idx < lines.len(),
"ループ本体 `.lua` 行 {loop_lua_line} は生成出力の範囲内"
);
let for_before = lines[..body_idx]
.iter()
.rposition(|l| l.contains("for ") && l.contains(" do"));
assert!(
for_before.is_some(),
"6.2(b): ループ本体 `.lua` 行 {loop_lua_line} の手前に `for ... do` が存在する \
(生成コード: {lines:#?})"
);
let end_after = lines[body_idx + 1..]
.iter()
.any(|l| l.trim() == "end");
assert!(
end_after,
"6.2(b): ループ本体 `.lua` 行 {loop_lua_line} の後ろにループ終端 `end` が存在する"
);
assert!(
lines[body_idx].contains("total = total + i"),
"6.2(b): ループ本体 `.lua` 行 {loop_lua_line} は累積式(毎反復実行)である: {:?}",
lines[body_idx]
);
}