Support printing can decls in uitest

This commit is contained in:
Ayaz Hafiz 2023-03-31 14:34:06 -05:00
parent d891dd829f
commit a10ce77584
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
6 changed files with 193 additions and 89 deletions

View file

@ -33,7 +33,7 @@ mod solve_expr {
..
},
src,
) = run_load_and_infer(src)?;
) = run_load_and_infer(src, false)?;
let mut can_problems = can_problems.remove(&home).unwrap_or_default();
let type_problems = type_problems.remove(&home).unwrap_or_default();
@ -113,7 +113,7 @@ mod solve_expr {
interns,
abilities_store,
..
} = run_load_and_infer(src).unwrap().0;
} = run_load_and_infer(src, false).unwrap().0;
let can_problems = can_problems.remove(&home).unwrap_or_default();
let type_problems = type_problems.remove(&home).unwrap_or_default();
@ -8318,61 +8318,35 @@ mod solve_expr {
);
}
#[test]
fn disjoint_nested_lambdas_result_in_disjoint_parents_issue_4712() {
infer_queries!(
indoc!(
r#"
app "test" provides [main] to "./platform"
//#[test]
//fn disjoint_nested_lambdas_result_in_disjoint_parents_issue_4712() {
// infer_queries!(
// indoc!(
// r#"
// "#
// ),
// @r###"
// v1 = {}
Parser a : {} -> a
// v2 = ""
v1 : {}
v1 = {}
// apply = \fnParser, valParser -> \{} -[9]-> (fnParser {}) valParser
v2 : Str
v2 = ""
// map = \simpleParser, transform -> apply \{} -[12]-> transform simpleParser
apply : Parser (a -> Str), a -> Parser Str
apply = \fnParser, valParser ->
\{} ->
(fnParser {}) (valParser)
// parseInput = \{} ->
// when [
// map v1 \{} -[13]-> "",
// map v2 \s -[14]-> s,
// ] is
// _ -> ""
map : a, (a -> Str) -> Parser Str
map = \simpleParser, transform ->
apply (\{} -> transform) simpleParser
// main = Bool.isEq (parseInput {}) ""
parseInput = \{} ->
when [ map v1 (\{} -> ""), map v2 (\s -> s) ] is
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ -> ""
main = parseInput {} == ""
"#
),
@r###"
v1 = {}
v2 = ""
apply = \fnParser, valParser -> \{} -[9]-> (fnParser {}) valParser
map = \simpleParser, transform -> apply \{} -[12]-> transform simpleParser
parseInput = \{} ->
when [
map v1 \{} -[13]-> "",
map v2 \s -[14]-> s,
] is
_ -> ""
main = Bool.isEq (parseInput {}) ""
[ map v1 (\{} -> ""), map v2 (\s -> s) ] : List (({} -[[9 (({} -[[12 (Str -[[14]]-> Str)]]-> (Str -[[14]]-> Str))) Str, 9 (({} -[[12 ({} -[[13]]-> Str)]]-> ({} -[[13]]-> Str))) {}]]-> Str))
"###
print_only_under_alias: true
print_can_decls: true
);
}
// [ map v1 (\{} -> ""), map v2 (\s -> s) ] : List (({} -[[9 (({} -[[12 (Str -[[14]]-> Str)]]-> (Str -[[14]]-> Str))) Str, 9 (({} -[[12 ({} -[[13]]-> Str)]]-> ({} -[[13]]-> Str))) {}]]-> Str))
// "###
// print_only_under_alias: true
// print_can_decls: true
// );
//}
}

View file

@ -9,7 +9,9 @@ use std::{
use lazy_static::lazy_static;
use libtest_mimic::{run, Arguments, Failed, Trial};
use regex::Regex;
use test_solve_helpers::{infer_queries, InferOptions, InferredHeader, InferredQuery};
use test_solve_helpers::{
infer_queries, InferOptions, InferredHeader, InferredProgram, InferredQuery,
};
fn main() -> Result<(), Box<dyn Error>> {
let args = Arguments::from_args();
@ -33,7 +35,11 @@ lazy_static! {
/// # +opt infer:<opt>
static ref RE_OPT_INFER: Regex =
Regex::new(r#"# +opt infer:(?P<opt>.*)"#).unwrap();
Regex::new(r#"# \+opt infer:(?P<opt>.*)"#).unwrap();
/// # +opt print:<opt>
static ref RE_OPT_PRINT: Regex =
Regex::new(r#"# \+opt print:(?P<opt>.*)"#).unwrap();
}
fn collect_uitest_files() -> io::Result<Vec<PathBuf>> {
@ -74,11 +80,11 @@ fn run_test(path: PathBuf) -> Result<(), Failed> {
let data = std::fs::read_to_string(&path)?;
let TestCase {
infer_options,
print_options,
source,
} = TestCase::parse(data)?;
let inferred_program = infer_queries(&source, infer_options)?;
let inferred_queries = inferred_program.into_sorted_queries();
{
let mut fd = fs::OpenOptions::new()
@ -86,7 +92,7 @@ fn run_test(path: PathBuf) -> Result<(), Failed> {
.truncate(true)
.open(&path)?;
assemble_query_output(&mut fd, &source, inferred_queries)?;
assemble_query_output(&mut fd, &source, inferred_program, print_options)?;
}
check_for_changes(&path)?;
@ -94,29 +100,37 @@ fn run_test(path: PathBuf) -> Result<(), Failed> {
Ok(())
}
const UITEST_HEADER: &str = "# uitest:";
const EMIT_HEADER: &str = "# emit:";
struct TestCase {
infer_options: InferOptions,
print_options: PrintOptions,
source: String,
}
#[derive(Default)]
struct PrintOptions {
can_decls: bool,
}
impl TestCase {
fn parse(mut data: String) -> Result<Self, Failed> {
// Drop anything following `# uitest:` header lines; that's the output.
if let Some(drop_at) = data.find(UITEST_HEADER) {
// Drop anything following `# emit:` header lines; that's the output.
if let Some(drop_at) = data.find(EMIT_HEADER) {
data.truncate(drop_at);
data.truncate(data.trim_end().len());
}
Ok(TestCase {
infer_options: Self::parse_infer_options(&data)?,
print_options: Self::parse_print_options(&data)?,
source: data,
})
}
fn parse_infer_options(data: &str) -> Result<InferOptions, Failed> {
let mut infer_opts = InferOptions::default();
infer_opts.no_promote = true;
let found_infer_opts = RE_OPT_INFER.captures_iter(data);
for infer_opt in found_infer_opts {
@ -130,6 +144,21 @@ impl TestCase {
Ok(infer_opts)
}
fn parse_print_options(data: &str) -> Result<PrintOptions, Failed> {
let mut print_opts = PrintOptions::default();
let found_infer_opts = RE_OPT_PRINT.captures_iter(data);
for infer_opt in found_infer_opts {
let opt = infer_opt.name("opt").unwrap().as_str();
match opt {
"can_decls" => print_opts.can_decls = true,
other => return Err(format!("unknown print option: {other}").into()),
}
}
Ok(print_opts)
}
}
fn check_for_changes(path: &Path) -> Result<(), Failed> {
@ -155,15 +184,17 @@ fn check_for_changes(path: &Path) -> Result<(), Failed> {
fn assemble_query_output(
writer: &mut impl io::Write,
source: &str,
sorted_queries: Vec<InferredQuery>,
inferred_program: InferredProgram,
print_options: PrintOptions,
) -> io::Result<()> {
// Reverse the queries so that we can pop them off the end as we pass through the lines.
let mut sorted_queries = sorted_queries;
let (mut sorted_queries, program) = inferred_program.decompose();
sorted_queries.reverse();
for (i, line) in source.lines().enumerate() {
let mut is_query_line = false;
// Write all elaborated query lines if applicable.
while matches!(
sorted_queries.last(),
Some(InferredQuery {
@ -180,11 +211,19 @@ fn assemble_query_output(
is_query_line = true;
}
// Otherwise, write the Roc source line.
if !is_query_line {
write!(writer, "{line}\n")?;
writeln!(writer, "{line}")?;
}
}
// Finish up with any remaining print options we were asked to provide.
let PrintOptions { can_decls } = print_options;
if can_decls {
writeln!(writer, "\n{EMIT_HEADER}can_decls")?;
program.write_can_decls(writer)?;
}
Ok(())
}

View file

@ -0,0 +1,45 @@
# +opt print:can_decls
# +opt infer:print_only_under_alias
app "test" provides [main] to "./platform"
Parser a : {} -> a
v1 : {}
v1 = {}
v2 : Str
v2 = ""
apply : Parser (a -> Str), a -> Parser Str
apply = \fnParser, valParser ->
\{} ->
(fnParser {}) (valParser)
map : a, (a -> Str) -> Parser Str
map = \simpleParser, transform ->
apply (\{} -> transform) simpleParser
parseInput = \{} ->
when [ map v1 (\{} -> ""), map v2 (\s -> s) ] is
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ List (({} -[[9 (({} -[[12 (Str -[[14]]-> Str)]]-> (Str -[[14]]-> Str))) Str, 9 (({} -[[12 ({} -[[13]]-> Str)]]-> ({} -[[13]]-> Str))) {}]]-> Str))
_ -> ""
main = parseInput {} == ""
# emit:can_decls
v1 = {}
v2 = ""
apply = \fnParser, valParser -> \{} -[9]-> (fnParser {}) valParser
map = \simpleParser, transform -> apply \{} -[12]-> transform simpleParser
parseInput = \{} ->
when [
map v1 \{} -[13]-> "",
map v2 \s -[14]-> s,
] is
_ -> ""
main = Bool.isEq (parseInput {}) ""