luaur_analysis/functions/
parse_fragment.rs1use 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}