Recursing through the ast to find the lists.

This commit is contained in:
Tom Alexander 2023-08-17 05:18:51 -04:00
parent 4b9e84375e
commit 91e9645c37
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -7,30 +7,32 @@ pub fn build_owner_tree<'a>(
ast_raw: &'a str, ast_raw: &'a str,
) -> Result<OwnerTree, Box<dyn std::error::Error + 'a>> { ) -> Result<OwnerTree, Box<dyn std::error::Error + 'a>> {
let (_remaining, parsed_sexp) = sexp_with_padding(ast_raw)?; let (_remaining, parsed_sexp) = sexp_with_padding(ast_raw)?;
let lists = find_lists_in_document(&parsed_sexp)?; let lists = find_lists_in_document(body, &parsed_sexp)?;
Ok(OwnerTree { Ok(OwnerTree {
input: body.to_owned(),
ast: ast_raw.to_owned(), ast: ast_raw.to_owned(),
children: lists, lists,
}) })
} }
#[derive(Serialize)] #[derive(Serialize)]
pub struct OwnerTree { pub struct OwnerTree {
input: String,
ast: String, ast: String,
children: Vec<PlainList>, lists: Vec<PlainList>,
} }
#[derive(Serialize)] #[derive(Serialize)]
pub struct PlainList { pub struct PlainList {
position: SourceRange, position: SourceRange,
children: Vec<PlainListItem>, items: Vec<PlainListItem>,
} }
#[derive(Serialize)] #[derive(Serialize)]
pub struct PlainListItem { pub struct PlainListItem {
position: SourceRange, position: SourceRange,
children: Vec<PlainListItem>, lists: Vec<PlainList>,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -42,6 +44,7 @@ pub struct SourceRange {
} }
fn find_lists_in_document<'a>( fn find_lists_in_document<'a>(
original_source: &str,
current_token: &Token<'a>, current_token: &Token<'a>,
) -> Result<Vec<PlainList>, Box<dyn std::error::Error>> { ) -> Result<Vec<PlainList>, Box<dyn std::error::Error>> {
// DFS looking for top-level lists // DFS looking for top-level lists
@ -53,12 +56,91 @@ fn find_lists_in_document<'a>(
// skip 2 to skip token name and standard properties // skip 2 to skip token name and standard properties
for child_token in children.iter().skip(2) { for child_token in children.iter().skip(2) {
found_lists.extend(recurse_token(child_token)?); found_lists.extend(recurse_token(original_source, child_token)?);
} }
Ok(found_lists) Ok(found_lists)
} }
fn recurse_token<'a>(
original_source: &str,
current_token: &Token<'a>,
) -> Result<Vec<PlainList>, Box<dyn std::error::Error>> {
match current_token {
Token::Atom(_) | Token::TextWithProperties(_) => Ok(Vec::new()),
Token::List(_) => {
let new_lists = find_lists_in_list(original_source, current_token)?;
Ok(new_lists)
}
Token::Vector(_) => {
let new_lists = find_lists_in_vector(original_source, current_token)?;
Ok(new_lists)
}
}
}
fn find_lists_in_list<'a>(
original_source: &str,
current_token: &Token<'a>,
) -> Result<Vec<PlainList>, Box<dyn std::error::Error>> {
let mut found_lists = Vec::new();
let children = current_token.as_list()?;
if assert_name(current_token, "plain-list").is_ok() {
// Found a list!
let mut found_items = Vec::new();
// skip 2 to skip token name and standard properties
for child_token in children.iter().skip(2) {
found_items.push(get_item_in_list(original_source, child_token)?);
}
found_lists.push(PlainList {
position: get_bounds(original_source, current_token)?,
items: found_items,
});
} else {
// skip 2 to skip token name and standard properties
for child_token in children.iter().skip(2) {
found_lists.extend(recurse_token(original_source, child_token)?);
}
}
Ok(found_lists)
}
fn find_lists_in_vector<'a>(
original_source: &str,
current_token: &Token<'a>,
) -> Result<Vec<PlainList>, Box<dyn std::error::Error>> {
let mut found_lists = Vec::new();
let children = current_token.as_vector()?;
for child_token in children.iter() {
found_lists.extend(recurse_token(original_source, child_token)?);
}
Ok(found_lists)
}
fn get_item_in_list<'a>(
original_source: &str,
current_token: &Token<'a>,
) -> Result<PlainListItem, Box<dyn std::error::Error>> {
let mut found_lists = Vec::new();
let children = current_token.as_list()?;
let token_name = "item";
assert_name(current_token, token_name)?;
// skip 2 to skip token name and standard properties
for child_token in children.iter().skip(2) {
found_lists.extend(recurse_token(original_source, child_token)?);
}
Ok(PlainListItem {
position: get_bounds(original_source, current_token)?,
lists: found_lists,
})
}
fn assert_name<'s>(emacs: &'s Token<'s>, name: &str) -> Result<(), Box<dyn std::error::Error>> { fn assert_name<'s>(emacs: &'s Token<'s>, name: &str) -> Result<(), Box<dyn std::error::Error>> {
let children = emacs.as_list()?; let children = emacs.as_list()?;
let first_child = children let first_child = children
@ -75,48 +157,61 @@ fn assert_name<'s>(emacs: &'s Token<'s>, name: &str) -> Result<(), Box<dyn std::
Ok(()) Ok(())
} }
fn recurse_token<'a>( fn get_bounds<'s>(
current_token: &Token<'a>, original_source: &'s str,
) -> Result<Vec<PlainList>, Box<dyn std::error::Error>> { emacs: &'s Token<'s>,
match current_token { ) -> Result<SourceRange, Box<dyn std::error::Error>> {
Token::Atom(_) | Token::TextWithProperties(_) => Ok(Vec::new()), let children = emacs.as_list()?;
Token::List(_) => { let attributes_child = children
let new_lists = find_lists_in_list(current_token)?; .iter()
Ok(new_lists) .nth(1)
} .ok_or("Should have an attributes child.")?;
Token::Vector(_) => { let attributes_map = attributes_child.as_map()?;
let new_lists = find_lists_in_vector(current_token)?; let standard_properties = attributes_map.get(":standard-properties");
Ok(new_lists) let (begin, end) = if standard_properties.is_some() {
} let std_props = standard_properties
} .expect("if statement proves its Some")
} .as_vector()?;
let begin = std_props
fn find_lists_in_list<'a>( .get(0)
current_token: &Token<'a>, .ok_or("Missing first element in standard properties")?
) -> Result<Vec<PlainList>, Box<dyn std::error::Error>> { .as_atom()?;
let mut found_lists = Vec::new(); let end = std_props
let children = current_token.as_list()?; .get(1)
if assert_name(current_token, "plain-list").is_ok() { .ok_or("Missing first element in standard properties")?
// Found a list! .as_atom()?;
} (begin, end)
} else {
// skip 2 to skip token name and standard properties let begin = attributes_map
for child_token in children.iter().skip(2) { .get(":begin")
found_lists.extend(recurse_token(child_token)?); .ok_or("Missing :begin attribute.")?
} .as_atom()?;
let end = attributes_map
Ok(found_lists) .get(":end")
} .ok_or("Missing :end attribute.")?
.as_atom()?;
fn find_lists_in_vector<'a>( (begin, end)
current_token: &Token<'a>, };
) -> Result<Vec<PlainList>, Box<dyn std::error::Error>> { let begin = begin.parse::<u32>()?;
let mut found_lists = Vec::new(); let end = end.parse::<u32>()?;
let children = current_token.as_vector()?; let start_line = original_source
.chars()
for child_token in children.iter() { .into_iter()
found_lists.extend(recurse_token(child_token)?); .take(usize::try_from(begin)? - 1)
} .filter(|x| *x == '\n')
.count()
Ok(found_lists) + 1;
let end_line = original_source
.chars()
.into_iter()
.take(usize::try_from(end)? - 1)
.filter(|x| *x == '\n')
.count()
+ 1;
Ok(SourceRange {
start_line: u32::try_from(start_line)?,
end_line: u32::try_from(end_line)?,
start_character: begin,
end_character: end,
})
} }