Recursing through the ast to find the lists.
This commit is contained in:
parent
4b9e84375e
commit
91e9645c37
@ -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,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user