perl_parser/incremental/
state.rs1use crate::incremental::checkpoint::{LexCheckpoint, ParseCheckpoint, ScopeSnapshot};
2use crate::incremental::lex::create_lex_checkpoints;
3use perl_lexer::{PerlLexer, Token, TokenType};
4use perl_line_index::LineIndex;
5use perl_parser_core::ast::{Node, NodeKind, SourceLocation};
6use perl_parser_core::parser::Parser;
7use ropey::Rope;
8
9#[derive(Clone)]
10pub struct IncrementalState {
11 pub rope: Rope,
12 pub line_index: LineIndex,
13 pub lex_checkpoints: Vec<LexCheckpoint>,
14 pub parse_checkpoints: Vec<ParseCheckpoint>,
15 pub ast: Node,
16 pub tokens: Vec<Token>,
17 pub source: String,
18}
19
20impl IncrementalState {
21 pub fn new(source: String) -> Self {
22 let rope = Rope::from_str(&source);
23 let line_index = LineIndex::new(&source);
24 let mut parser = Parser::new(&source);
25 let ast = match parser.parse() {
26 Ok(ast) => ast,
27 Err(e) => Node::new(
28 NodeKind::Error {
29 message: e.to_string(),
30 expected: vec![],
31 found: None,
32 partial: None,
33 },
34 SourceLocation { start: 0, end: source.len() },
35 ),
36 };
37 let mut lexer = PerlLexer::new(&source);
38 let mut tokens = Vec::new();
39 while let Some(token) = lexer.next_token() {
40 if token.token_type == TokenType::EOF {
41 break;
42 }
43 tokens.push(token);
44 }
45 let lex_checkpoints = create_lex_checkpoints(&tokens, &line_index);
46 let parse_checkpoints = Self::create_parse_checkpoints(&ast);
47 Self { rope, line_index, lex_checkpoints, parse_checkpoints, ast, tokens, source }
48 }
49 pub fn find_lex_checkpoint(&self, byte: usize) -> Option<&LexCheckpoint> {
50 self.lex_checkpoints.iter().rev().find(|cp| cp.byte <= byte)
51 }
52 pub fn find_parse_checkpoint(&self, byte: usize) -> Option<&ParseCheckpoint> {
53 self.parse_checkpoints.iter().rev().find(|cp| cp.byte <= byte)
54 }
55
56 pub(crate) fn create_parse_checkpoints(ast: &Node) -> Vec<ParseCheckpoint> {
57 let mut checkpoints = vec![];
58 let mut scope = ScopeSnapshot::default();
59 walk_ast_for_checkpoints(ast, &mut checkpoints, &mut scope, 0);
60 checkpoints
61 }
62}
63
64fn walk_ast_for_checkpoints(
65 node: &Node,
66 checkpoints: &mut Vec<ParseCheckpoint>,
67 scope: &mut ScopeSnapshot,
68 node_id: usize,
69) {
70 match &node.kind {
71 NodeKind::Package { name, .. } => {
72 scope.package_name = name.clone();
73 checkpoints.push(ParseCheckpoint {
74 byte: node.location.start,
75 scope_snapshot: scope.clone(),
76 node_id,
77 });
78 }
79 NodeKind::Subroutine { .. } | NodeKind::Block { .. } => checkpoints.push(ParseCheckpoint {
80 byte: node.location.start,
81 scope_snapshot: scope.clone(),
82 node_id,
83 }),
84 NodeKind::VariableDeclaration { variable, .. } => {
85 if let NodeKind::Variable { name, sigil, .. } = &variable.kind {
86 scope.locals.push(format!("{}{}", sigil, name));
87 }
88 }
89 NodeKind::VariableListDeclaration { variables, .. } => {
90 for var in variables {
91 if let NodeKind::Variable { name, sigil, .. } = &var.kind {
92 scope.locals.push(format!("{}{}", sigil, name));
93 }
94 }
95 }
96 _ => {}
97 }
98 match &node.kind {
99 NodeKind::Program { statements } | NodeKind::Block { statements } => {
100 for (i, stmt) in statements.iter().enumerate() {
101 walk_ast_for_checkpoints(
102 stmt,
103 checkpoints,
104 scope,
105 node_id.wrapping_mul(101).wrapping_add(i),
106 );
107 }
108 }
109 _ => {}
110 }
111}