Skip to main content

luaur_analysis/functions/
parse_fragment.rs

1use crate::functions::find_ancestry_at_position_for_autocomplete_ast_query_alt_b::find_ancestry_at_position_for_autocomplete_ast_stat_block_position;
2use crate::functions::find_ancestry_for_fragment_parse::find_ancestry_for_fragment_parse;
3use crate::functions::get_document_offsets::get_document_offsets;
4use crate::records::fragment_parse_result::FragmentParseResult;
5use alloc::boxed::Box;
6use alloc::string::String;
7use luaur_ast::records::allocator::Allocator;
8use luaur_ast::records::ast_name_table::AstNameTable;
9use luaur_ast::records::ast_stat::AstStat;
10use luaur_ast::records::ast_stat_block::AstStatBlock;
11use luaur_ast::records::fragment_parse_resume_settings::FragmentParseResumeSettings;
12use luaur_ast::records::parse_options::ParseOptions;
13use luaur_ast::records::parser::Parser;
14use luaur_ast::records::position::Position;
15
16pub fn parse_fragment(
17    stale: *mut AstStatBlock,
18    most_recent_parse: *mut AstStatBlock,
19    names: *mut AstNameTable,
20    src: &str,
21    cursor_pos: &Position,
22    fragment_end_position: Option<Position>,
23) -> Option<FragmentParseResult> {
24    if most_recent_parse.is_null() {
25        return None;
26    }
27
28    let result = find_ancestry_for_fragment_parse(stale, *cursor_pos, most_recent_parse);
29    let mut nearest_statement = result.nearestStatement;
30
31    let start_pos = result.fragmentSelectionRegion.begin;
32    let end_pos = fragment_end_position.unwrap_or(result.fragmentSelectionRegion.end);
33    let (offset_start, parse_length) = get_document_offsets(src, &start_pos, &end_pos);
34    let fragment_source = &src[offset_start..offset_start + parse_length];
35
36    let mut fragment_alloc = Box::new(Allocator::allocator());
37    let mut parse_options = ParseOptions::default();
38    parse_options.allow_declaration_syntax = false;
39    parse_options.capture_comments = true;
40    parse_options.parse_fragment = Some(FragmentParseResumeSettings::new(
41        result.localMap,
42        result.localStack,
43        start_pos,
44    ));
45
46    let parse_result = unsafe {
47        Parser::parse(
48            fragment_source,
49            parse_length,
50            &mut *names,
51            &mut *fragment_alloc,
52            parse_options,
53        )
54    };
55
56    if parse_result.root.is_null() {
57        return None;
58    }
59
60    let mut fabricated_ancestry =
61        find_ancestry_at_position_for_autocomplete_ast_stat_block_position(
62            unsafe { &mut *most_recent_parse },
63            *cursor_pos,
64        );
65    let fragment_ancestry = find_ancestry_at_position_for_autocomplete_ast_stat_block_position(
66        unsafe { &mut *parse_result.root },
67        *cursor_pos,
68    );
69
70    let mut back = fabricated_ancestry.len();
71    for fragment_node in fragment_ancestry.iter().rev() {
72        if back == 0 {
73            break;
74        }
75
76        back -= 1;
77        let fabricated_node = fabricated_ancestry[back];
78        if !fragment_node.is_null()
79            && !fabricated_node.is_null()
80            && unsafe { (**fragment_node).class_index == (*fabricated_node).class_index }
81        {
82            fabricated_ancestry[back] = *fragment_node;
83        }
84    }
85
86    if nearest_statement.is_null() {
87        nearest_statement = parse_result.root as *mut AstStat;
88    }
89
90    let scope_pos = if result.parentBlock.is_null() {
91        Position { line: 0, column: 0 }
92    } else {
93        unsafe { (*result.parentBlock).base.base.location.begin }
94    };
95
96    Some(FragmentParseResult {
97        fragment_to_parse: String::from(fragment_source),
98        root: parse_result.root,
99        ancestry: fabricated_ancestry,
100        nearest_statement,
101        comment_locations: parse_result.comment_locations,
102        alloc: fragment_alloc,
103        scope_pos,
104    })
105}