mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Stub out the rest of uitest
This commit is contained in:
parent
3aaf771543
commit
54d6bf7747
3 changed files with 170 additions and 40 deletions
|
@ -9,7 +9,8 @@ use std::{
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use libtest_mimic::{run, Arguments, Failed, Trial};
|
use libtest_mimic::{run, Arguments, Failed, Trial};
|
||||||
use regex::Regex;
|
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>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let args = Arguments::from_args();
|
let args = Arguments::from_args();
|
||||||
|
@ -77,7 +78,18 @@ fn run_test(path: PathBuf) -> Result<(), Failed> {
|
||||||
source,
|
source,
|
||||||
} = TestCase::parse(data)?;
|
} = 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)?;
|
check_for_changes(&path)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -150,3 +162,63 @@ fn check_for_changes(path: &Path) -> Result<(), Failed> {
|
||||||
|
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
app "test" provides [main] to "./platform"
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
main = Bool.isEq Bool.true Bool.false
|
main = Bool.isEq Bool.true Bool.false
|
||||||
# ^^^^^^^^^
|
# ^^^^^^^^^ Eq#Bool.isEq(9) : Bool, Bool -[[Bool.structuralEq(11)]]-> Bool
|
||||||
|
|
|
@ -134,8 +134,13 @@ lazy_static! {
|
||||||
Regex::new(r#"(?P<where>\^+)(?:\{-(?P<sub>\d+)\})?"#).unwrap();
|
Regex::new(r#"(?P<where>\^+)(?:\{-(?P<sub>\d+)\})?"#).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TypeQuery(Region);
|
pub struct TypeQuery {
|
||||||
|
query_region: Region,
|
||||||
|
source: String,
|
||||||
|
comment_column: u32,
|
||||||
|
source_line_column: LineColumn,
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse inference queries in a Roc program.
|
/// Parse inference queries in a Roc program.
|
||||||
/// See [RE_TYPE_QUERY].
|
/// See [RE_TYPE_QUERY].
|
||||||
|
@ -144,6 +149,16 @@ fn parse_queries(src: &str) -> Vec<TypeQuery> {
|
||||||
let mut queries = vec![];
|
let mut queries = vec![];
|
||||||
let mut consecutive_query_lines = 0;
|
let mut consecutive_query_lines = 0;
|
||||||
for (i, line) in src.lines().enumerate() {
|
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();
|
let mut queries_on_line = RE_TYPE_QUERY.captures_iter(line).into_iter().peekable();
|
||||||
|
|
||||||
if queries_on_line.peek().is_none() {
|
if queries_on_line.peek().is_none() {
|
||||||
|
@ -154,28 +169,46 @@ fn parse_queries(src: &str) -> Vec<TypeQuery> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for capture in queries_on_line {
|
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 wher = capture.name("where").unwrap();
|
||||||
let subtract_col = capture
|
let subtract_col = capture
|
||||||
.name("sub")
|
.name("sub")
|
||||||
.and_then(|m| str::parse(m.as_str()).ok())
|
.and_then(|m| str::parse(m.as_str()).ok())
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
let (start, end) = (wher.start() as u32, wher.end() as u32);
|
let (source_start, source_end) = (wher.start() as u32, wher.end() as u32);
|
||||||
let (start, end) = (start - subtract_col, end - subtract_col);
|
let (query_start, query_end) = (source_start - subtract_col, source_end - subtract_col);
|
||||||
|
|
||||||
let last_line = i as u32 - consecutive_query_lines;
|
let source_line_column = LineColumn {
|
||||||
let start_lc = LineColumn {
|
line: i as u32,
|
||||||
line: last_line,
|
column: source_start,
|
||||||
column: start,
|
|
||||||
};
|
};
|
||||||
let end_lc = LineColumn {
|
|
||||||
line: last_line,
|
|
||||||
column: end,
|
|
||||||
};
|
|
||||||
let lc_region = LineColumnRegion::new(start_lc, end_lc);
|
|
||||||
let region = line_info.convert_line_column_region(lc_region);
|
|
||||||
|
|
||||||
queries.push(TypeQuery(region));
|
let query_region = {
|
||||||
|
let last_line = i as u32 - consecutive_query_lines;
|
||||||
|
let query_start_lc = LineColumn {
|
||||||
|
line: last_line,
|
||||||
|
column: query_start,
|
||||||
|
};
|
||||||
|
let query_end_lc = LineColumn {
|
||||||
|
line: last_line,
|
||||||
|
column: query_end,
|
||||||
|
};
|
||||||
|
let query_lc_region = LineColumnRegion::new(query_start_lc, query_end_lc);
|
||||||
|
line_info.convert_line_column_region(query_lc_region)
|
||||||
|
};
|
||||||
|
|
||||||
|
queries.push(TypeQuery {
|
||||||
|
query_region,
|
||||||
|
source,
|
||||||
|
comment_column,
|
||||||
|
source_line_column,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queries
|
queries
|
||||||
|
@ -189,8 +222,13 @@ pub struct InferOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InferredQuery {
|
pub struct InferredQuery {
|
||||||
pub region: Region,
|
|
||||||
pub output: String,
|
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 {
|
pub struct InferredProgram {
|
||||||
|
@ -200,6 +238,15 @@ pub struct InferredProgram {
|
||||||
inferred_queries: Vec<InferredQuery>,
|
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>> {
|
pub fn infer_queries(src: &str, options: InferOptions) -> Result<InferredProgram, Box<dyn Error>> {
|
||||||
let (
|
let (
|
||||||
LoadedModule {
|
LoadedModule {
|
||||||
|
@ -239,12 +286,18 @@ pub fn infer_queries(src: &str, options: InferOptions) -> Result<InferredProgram
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut inferred_queries = Vec::with_capacity(queries.len());
|
let mut inferred_queries = Vec::with_capacity(queries.len());
|
||||||
for TypeQuery(region) in queries.into_iter() {
|
for TypeQuery {
|
||||||
let start = region.start().offset;
|
query_region,
|
||||||
let end = region.end().offset;
|
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 text = &src[start as usize..end as usize];
|
||||||
let var = find_type_at(region, &declarations)
|
let var = find_type_at(query_region, &declarations)
|
||||||
.ok_or_else(|| format!("No type for {:?} ({:?})!", &text, region))?;
|
.ok_or_else(|| format!("No type for {:?} ({:?})!", &text, query_region))?;
|
||||||
|
|
||||||
let snapshot = subs.snapshot();
|
let snapshot = subs.snapshot();
|
||||||
let actual_str = name_and_print_var(
|
let actual_str = name_and_print_var(
|
||||||
|
@ -261,25 +314,30 @@ pub fn infer_queries(src: &str, options: InferOptions) -> Result<InferredProgram
|
||||||
);
|
);
|
||||||
subs.rollback_to(snapshot);
|
subs.rollback_to(snapshot);
|
||||||
|
|
||||||
let elaborated =
|
let elaborated = match find_ability_member_and_owning_type_at(
|
||||||
match find_ability_member_and_owning_type_at(region, &declarations, &abilities_store) {
|
query_region,
|
||||||
Some((spec_type, spec_symbol)) => {
|
&declarations,
|
||||||
format!(
|
&abilities_store,
|
||||||
"{}#{}({}) : {}",
|
) {
|
||||||
spec_type.as_str(&interns),
|
Some((spec_type, spec_symbol)) => {
|
||||||
text,
|
format!(
|
||||||
spec_symbol.ident_id().index(),
|
"{}#{}({}) : {}",
|
||||||
actual_str
|
spec_type.as_str(&interns),
|
||||||
)
|
text,
|
||||||
}
|
spec_symbol.ident_id().index(),
|
||||||
None => {
|
actual_str
|
||||||
format!("{} : {}", text, actual_str)
|
)
|
||||||
}
|
}
|
||||||
};
|
None => {
|
||||||
|
format!("{} : {}", text, actual_str)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
inferred_queries.push(InferredQuery {
|
inferred_queries.push(InferredQuery {
|
||||||
region,
|
|
||||||
output: elaborated,
|
output: elaborated,
|
||||||
|
comment_column,
|
||||||
|
source_line_column,
|
||||||
|
source,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue