Phase 5: Editor und inkrementellen Compiler implementieren und archivieren
This commit is contained in:
162
crates/tb-vm/tests/incremental.rs
Normal file
162
crates/tb-vm/tests/incremental.rs
Normal file
@@ -0,0 +1,162 @@
|
||||
use tb_frontend::{
|
||||
forms::FormCatalog,
|
||||
source::{SourceSegment, SourceUnit},
|
||||
};
|
||||
use tb_ui::frm::{self, FormFile};
|
||||
use tb_vm::{compile_project, project::ProjectCompiler};
|
||||
fn unit(name: &str, text: &str) -> SourceUnit {
|
||||
SourceUnit::new(name, &format!("{name}.bas"), text)
|
||||
}
|
||||
fn compare(cache: &mut ProjectCompiler, units: &[SourceUnit], forms: &[FormFile]) -> bool {
|
||||
let mut catalog = FormCatalog::default();
|
||||
for f in forms {
|
||||
catalog.append(&f.catalog());
|
||||
}
|
||||
let a = cache.compile("APP", units, &catalog, forms);
|
||||
let b = compile_project("APP", units, &catalog, forms);
|
||||
match (a, b) {
|
||||
(Ok(a), Ok(b)) => {
|
||||
assert_eq!(a.to_tbc(), b.to_tbc());
|
||||
true
|
||||
}
|
||||
(Err(a), Err(b)) => {
|
||||
assert_eq!(
|
||||
a.iter().map(ToString::to_string).collect::<Vec<_>>(),
|
||||
b.iter().map(ToString::to_string).collect::<Vec<_>>()
|
||||
);
|
||||
false
|
||||
}
|
||||
(a, b) => panic!("cache/full mismatch {a:?} / {b:?}"),
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn cached_private_edits_parse_and_compile_only_changed_modules() {
|
||||
let mut c = ProjectCompiler::default();
|
||||
let mut units = vec![
|
||||
unit("A", "CALL Work\nEND"),
|
||||
unit("B", "SUB Work\nPRINT 1\nEND SUB"),
|
||||
unit("C", "SUB Independent\nPRINT 3\nEND SUB"),
|
||||
];
|
||||
assert!(compare(&mut c, &units, &[]));
|
||||
assert_eq!(c.stats.compiled, 3);
|
||||
assert!(compare(&mut c, &units, &[]));
|
||||
assert_eq!(
|
||||
(c.stats.parsed, c.stats.compiled, c.stats.reused),
|
||||
(0, 0, 3)
|
||||
);
|
||||
units[1].segments[0].text = units[1].segments[0].text.replace("PRINT 1", "PRINT 2");
|
||||
assert!(compare(&mut c, &units, &[]));
|
||||
assert_eq!(
|
||||
(c.stats.parsed, c.stats.compiled, c.stats.reused),
|
||||
(1, 1, 2)
|
||||
);
|
||||
units[1].segments[0].text = "SUB Work\nPRINT 2\nEND SUB\nSUB Second\nPRINT 4\nEND SUB".into();
|
||||
assert!(compare(&mut c, &units, &[]));
|
||||
units[1].segments[0].text = units[1].segments[0]
|
||||
.text
|
||||
.replace("PRINT 2", "PRINT 2\nPRINT 3");
|
||||
assert!(compare(&mut c, &units, &[]));
|
||||
assert_eq!(
|
||||
(c.stats.compiled, c.stats.reused),
|
||||
(1, 2),
|
||||
"Verschobene fremde Prozedurzeilen ändern keinen Importvertrag"
|
||||
);
|
||||
units[1].segments[0].text = "SUB Work\nPRINT )\nEND SUB".into();
|
||||
assert!(!compare(&mut c, &units, &[]));
|
||||
units[1].segments[0].text = "SUB Work\nPRINT 5\nEND SUB".into();
|
||||
assert!(compare(&mut c, &units, &[]));
|
||||
}
|
||||
#[test]
|
||||
fn constants_types_common_removed_symbols_and_order_match_full_compiler() {
|
||||
let mut c = ProjectCompiler::default();
|
||||
let mut u = vec![
|
||||
unit(
|
||||
"A",
|
||||
"CONST A=2\nTYPE T\nx AS INTEGER\nEND TYPE\nCOMMON SHARED N%\n",
|
||||
),
|
||||
unit("B", "CONST B=A+1\n"),
|
||||
unit(
|
||||
"C",
|
||||
"DIM value AS T\nvalue.x=B\nCOMMON SHARED N%\nN%=B\nPRINT value.x\n",
|
||||
),
|
||||
];
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
u[0].segments[0].text = u[0].segments[0].text.replace("A=2", "A=4");
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
u[0].segments[0].text = u[0].segments[0].text.replace("INTEGER", "LONG");
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
u[0].segments[0].text = u[0].segments[0].text.replace("N%", "N$");
|
||||
compare(&mut c, &u, &[]);
|
||||
u[0].segments[0].text = u[0].segments[0].text.replace("CONST A=4", "' removed");
|
||||
assert!(!compare(&mut c, &u, &[]));
|
||||
u.swap(0, 2);
|
||||
assert!(!compare(&mut c, &u, &[]));
|
||||
u.remove(0);
|
||||
compare(&mut c, &u, &[]);
|
||||
}
|
||||
#[test]
|
||||
fn includes_source_ids_data_and_forms_relink_without_patching_old_products() {
|
||||
let mut c = ProjectCompiler::default();
|
||||
let mut u = vec![
|
||||
unit(
|
||||
"A",
|
||||
"DATA 3,\"Hi\"\nREAD a%, b$\nPRINT a%;b$\nCALL Work\nEND",
|
||||
),
|
||||
unit("B", "SUB Work\nPRINT 2\nEND SUB"),
|
||||
];
|
||||
u[0].segments.insert(
|
||||
0,
|
||||
SourceSegment {
|
||||
file: "shared.bi".into(),
|
||||
first_line: 7,
|
||||
text: "CONST N=1\n".into(),
|
||||
},
|
||||
);
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
u[0].segments[0].text = "CONST N=2\n".into();
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
u.swap(0, 1);
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
u[0].segments.insert(
|
||||
0,
|
||||
SourceSegment {
|
||||
file: "extra.bi".into(),
|
||||
first_line: 1,
|
||||
text: "' extra source\n".into(),
|
||||
},
|
||||
);
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
for index in [None, Some(0), Some(1)] {
|
||||
let property = index.map_or(String::new(), |index| format!(" Index = {index}\n"));
|
||||
let text = format!(
|
||||
"VERSION 1.00\nBEGIN Form Main\n BEGIN CommandButton Button\n{property} END\nEND\n"
|
||||
);
|
||||
let form = frm::read_text("Main.frm", &text).unwrap();
|
||||
let units = [unit("Main", "'$FORM\n")];
|
||||
assert!(compare(&mut c, &units, &[form]));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unused_constants_do_not_invalidate_independent_units_and_declare_changes_do() {
|
||||
let mut c = ProjectCompiler::default();
|
||||
let mut u = vec![
|
||||
unit("A", "CONST A=1\n"),
|
||||
unit("B", "CONST B=A+1\n"),
|
||||
unit("C", "PRINT B\n"),
|
||||
unit("D", "PRINT 7\n"),
|
||||
];
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
u[0].segments[0].text = "CONST A=3\n".into();
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
assert_eq!((c.stats.compiled, c.stats.reused), (3, 1));
|
||||
let mut u = vec![
|
||||
unit("A", "DECLARE SUB Work(n%)\nCALL Work(1)\nEND"),
|
||||
unit("B", "SUB Work(n%)\nPRINT n%\nEND SUB"),
|
||||
];
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
u[1].segments[0].text = "SUB Work(n$)\nPRINT n$\nEND SUB".into();
|
||||
assert!(!compare(&mut c, &u, &[]));
|
||||
u[0].segments[0].text = "DECLARE SUB Work(n$)\nCALL Work(\"ok\")\nEND".into();
|
||||
assert!(compare(&mut c, &u, &[]));
|
||||
}
|
||||
Reference in New Issue
Block a user