Stub out the rest of uitest

This commit is contained in:
Ayaz Hafiz 2023-03-31 13:39:33 -05:00
parent 3aaf771543
commit 54d6bf7747
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
3 changed files with 170 additions and 40 deletions

View file

@ -9,7 +9,8 @@ use std::{
use lazy_static::lazy_static;
use libtest_mimic::{run, Arguments, Failed, Trial};
use regex::Regex;
use test_solve_helpers::InferOptions;
use roc_region::all::LineColumn;
use test_solve_helpers::{infer_queries, InferOptions, InferredQuery};
fn main() -> Result<(), Box<dyn Error>> {
let args = Arguments::from_args();
@ -77,7 +78,18 @@ fn run_test(path: PathBuf) -> Result<(), Failed> {
source,
} = TestCase::parse(data)?;
fs::write(&path, &source)?;
let inferred_program = infer_queries(&source, infer_options)?;
let inferred_queries = inferred_program.into_sorted_queries();
{
let mut fd = fs::OpenOptions::new()
.write(true)
.truncate(true)
.open(&path)?;
assemble_query_output(&mut fd, &source, inferred_queries)?;
}
check_for_changes(&path)?;
Ok(())
@ -150,3 +162,63 @@ fn check_for_changes(path: &Path) -> Result<(), Failed> {
Ok(())
}
/// Assemble the output for a test, with queries elaborated in-line.
fn assemble_query_output(
writer: &mut impl io::Write,
source: &str,
sorted_queries: Vec<InferredQuery>,
) -> 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;
sorted_queries.reverse();
for (i, line) in source.lines().enumerate() {
let mut is_query_line = false;
while matches!(
sorted_queries.last(),
Some(InferredQuery {
source_line_column,
..
}) if source_line_column.line == i as _
) {
let InferredQuery {
output,
comment_column,
source_line_column,
source,
} = sorted_queries.pop().unwrap();
reconstruct_comment_line(writer, &source, source_line_column, comment_column, output)?;
writeln!(writer)?;
is_query_line = true;
}
if !is_query_line {
write!(writer, "{line}\n")?;
}
}
Ok(())
}
fn reconstruct_comment_line(
writer: &mut impl io::Write,
source: &str,
source_line_column: LineColumn,
comment_column: u32,
output: String,
) -> io::Result<()> {
for _ in 0..comment_column {
write!(writer, " ")?;
}
write!(writer, "#")?;
for _ in 0..(source_line_column.column - comment_column - 1) {
write!(writer, " ")?;
}
write!(writer, "{source} {output}")?;
Ok(())
}

View file

@ -1,4 +1,4 @@
app "test" provides [main] to "./platform"
main = Bool.isEq Bool.true Bool.false
# ^^^^^^^^^
# ^^^^^^^^^ Eq#Bool.isEq(9) : Bool, Bool -[[Bool.structuralEq(11)]]-> Bool

View file

@ -134,8 +134,13 @@ lazy_static! {
Regex::new(r#"(?P<where>\^+)(?:\{-(?P<sub>\d+)\})?"#).unwrap();
}
#[derive(Debug, Clone, Copy)]
pub struct TypeQuery(Region);
#[derive(Debug, Clone)]
pub struct TypeQuery {
query_region: Region,
source: String,
comment_column: u32,
source_line_column: LineColumn,
}
/// Parse inference queries in a Roc program.
/// See [RE_TYPE_QUERY].
@ -144,6 +149,16 @@ fn parse_queries(src: &str) -> Vec<TypeQuery> {
let mut queries = vec![];
let mut consecutive_query_lines = 0;
for (i, line) in src.lines().enumerate() {
// If this is a query line, it should start with a comment somewhere before the query
// lines.
let comment_column = match line.find("#") {
Some(i) => i as _,
None => {
consecutive_query_lines = 0;
continue;
}
};
let mut queries_on_line = RE_TYPE_QUERY.captures_iter(line).into_iter().peekable();
if queries_on_line.peek().is_none() {
@ -154,28 +169,46 @@ fn parse_queries(src: &str) -> Vec<TypeQuery> {
}
for capture in queries_on_line {
let source = capture
.get(0)
.expect("full capture must always exist")
.as_str()
.to_string();
let wher = capture.name("where").unwrap();
let subtract_col = capture
.name("sub")
.and_then(|m| str::parse(m.as_str()).ok())
.unwrap_or(0);
let (start, end) = (wher.start() as u32, wher.end() as u32);
let (start, end) = (start - subtract_col, end - subtract_col);
let (source_start, source_end) = (wher.start() as u32, wher.end() as u32);
let (query_start, query_end) = (source_start - subtract_col, source_end - subtract_col);
let source_line_column = LineColumn {
line: i as u32,
column: source_start,
};
let query_region = {
let last_line = i as u32 - consecutive_query_lines;
let start_lc = LineColumn {
let query_start_lc = LineColumn {
line: last_line,
column: start,
column: query_start,
};
let end_lc = LineColumn {
let query_end_lc = LineColumn {
line: last_line,
column: end,
column: query_end,
};
let query_lc_region = LineColumnRegion::new(query_start_lc, query_end_lc);
line_info.convert_line_column_region(query_lc_region)
};
let lc_region = LineColumnRegion::new(start_lc, end_lc);
let region = line_info.convert_line_column_region(lc_region);
queries.push(TypeQuery(region));
queries.push(TypeQuery {
query_region,
source,
comment_column,
source_line_column,
});
}
}
queries
@ -189,8 +222,13 @@ pub struct InferOptions {
}
pub struct InferredQuery {
pub region: Region,
pub output: String,
/// Where the comment before the query string was written in the source.
pub comment_column: u32,
/// Where the query string "^^^" itself was written in the source.
pub source_line_column: LineColumn,
/// The content of the query string.
pub source: String,
}
pub struct InferredProgram {
@ -200,6 +238,15 @@ pub struct InferredProgram {
inferred_queries: Vec<InferredQuery>,
}
impl InferredProgram {
/// Returns all inferred queries, sorted by their source location.
pub fn into_sorted_queries(self) -> Vec<InferredQuery> {
let mut inferred = self.inferred_queries;
inferred.sort_by_key(|iq| iq.source_line_column);
inferred
}
}
pub fn infer_queries(src: &str, options: InferOptions) -> Result<InferredProgram, Box<dyn Error>> {
let (
LoadedModule {
@ -239,12 +286,18 @@ pub fn infer_queries(src: &str, options: InferOptions) -> Result<InferredProgram
}
let mut inferred_queries = Vec::with_capacity(queries.len());
for TypeQuery(region) in queries.into_iter() {
let start = region.start().offset;
let end = region.end().offset;
for TypeQuery {
query_region,
source,
comment_column,
source_line_column,
} in queries.into_iter()
{
let start = query_region.start().offset;
let end = query_region.end().offset;
let text = &src[start as usize..end as usize];
let var = find_type_at(region, &declarations)
.ok_or_else(|| format!("No type for {:?} ({:?})!", &text, region))?;
let var = find_type_at(query_region, &declarations)
.ok_or_else(|| format!("No type for {:?} ({:?})!", &text, query_region))?;
let snapshot = subs.snapshot();
let actual_str = name_and_print_var(
@ -261,8 +314,11 @@ pub fn infer_queries(src: &str, options: InferOptions) -> Result<InferredProgram
);
subs.rollback_to(snapshot);
let elaborated =
match find_ability_member_and_owning_type_at(region, &declarations, &abilities_store) {
let elaborated = match find_ability_member_and_owning_type_at(
query_region,
&declarations,
&abilities_store,
) {
Some((spec_type, spec_symbol)) => {
format!(
"{}#{}({}) : {}",
@ -278,8 +334,10 @@ pub fn infer_queries(src: &str, options: InferOptions) -> Result<InferredProgram
};
inferred_queries.push(InferredQuery {
region,
output: elaborated,
comment_column,
source_line_column,
source,
});
}