oak_core/parser/
session.rs1use crate::{
2 Language,
3 lexer::{LexOutput, LexerCache, Token},
4 memory::arena::SyntaxArena,
5 tree::GreenNode,
6};
7use std::{cell::Cell, ptr::NonNull};
8
9pub trait ParseCache<L: Language>: LexerCache<L> {
11 fn arena(&self) -> &SyntaxArena;
13
14 fn old_tree(&self) -> Option<&GreenNode<'_, L>>;
16
17 fn lex_output(&self) -> Option<&LexOutput<L>>;
19
20 fn prepare_generation(&mut self);
22
23 fn commit_generation(&self, root: &GreenNode<L>);
25}
26
27pub struct ParseSession<L: Language + Send + Sync + 'static> {
32 arena_active: SyntaxArena,
34 arena_old: Option<SyntaxArena>,
36 last_root: Cell<Option<NonNull<GreenNode<'static, L>>>>,
38 last_lex: Option<LexOutput<L>>,
40}
41
42unsafe impl<L: Language + Send + Sync + 'static> Send for ParseSession<L> {}
43unsafe impl<L: Language + Send + Sync + 'static> Sync for ParseSession<L> {}
44
45impl<L: Language + Send + Sync + 'static> Default for ParseSession<L> {
46 fn default() -> Self {
47 Self::new(16)
48 }
49}
50
51impl<L: Language + Send + Sync + 'static> ParseSession<L> {
52 pub fn new(capacity: usize) -> Self {
54 Self { arena_active: SyntaxArena::new(capacity), arena_old: None, last_root: Cell::new(None), last_lex: None }
55 }
56}
57
58impl<L: Language + Send + Sync + 'static> ParseCache<L> for ParseSession<L> {
59 fn arena(&self) -> &SyntaxArena {
60 &self.arena_active
61 }
62
63 fn old_tree(&self) -> Option<&GreenNode<'_, L>> {
64 let ptr = self.last_root.get()?;
65 if self.arena_old.is_some() {
66 unsafe { Some(&*(ptr.as_ptr() as *const GreenNode<'_, L>)) }
68 }
69 else {
70 None
71 }
72 }
73
74 fn lex_output(&self) -> Option<&LexOutput<L>> {
75 self.last_lex.as_ref()
76 }
77
78 fn prepare_generation(&mut self) {
79 self.arena_old = Some(std::mem::replace(&mut self.arena_active, SyntaxArena::new(16)));
81
82 self.last_lex = None;
85 }
86
87 fn commit_generation(&self, root: &GreenNode<L>) {
88 unsafe {
90 self.last_root.set(Some(NonNull::new_unchecked(root as *const _ as *mut GreenNode<'static, L>)));
91 }
92 }
93}
94
95impl<L: Language + Send + Sync + 'static> LexerCache<L> for ParseSession<L> {
96 fn set_lex_output(&mut self, output: LexOutput<L>) {
97 self.last_lex = Some(output);
98 }
99
100 fn get_token(&self, index: usize) -> Option<Token<L::TokenType>> {
101 self.last_lex.as_ref()?.result.as_ref().ok()?.get(index).cloned()
102 }
103
104 fn count_tokens(&self) -> usize {
105 self.last_lex.as_ref().and_then(|out| out.result.as_ref().ok()).map(|tokens| tokens.len()).unwrap_or(0)
106 }
107
108 fn has_tokens(&self) -> bool {
109 self.last_lex.as_ref().and_then(|out| out.result.as_ref().ok()).map(|tokens| !tokens.is_empty()).unwrap_or(false)
110 }
111
112 fn get_tokens(&self) -> Option<&[Token<L::TokenType>]> {
113 self.last_lex.as_ref()?.result.as_ref().ok().map(|tokens| &**tokens)
114 }
115}
116
117impl<'a, L: Language, C: ParseCache<L> + ?Sized> ParseCache<L> for &'a mut C {
118 fn arena(&self) -> &SyntaxArena {
119 (**self).arena()
120 }
121
122 fn old_tree(&self) -> Option<&GreenNode<'_, L>> {
123 (**self).old_tree()
124 }
125
126 fn lex_output(&self) -> Option<&LexOutput<L>> {
127 (**self).lex_output()
128 }
129
130 fn prepare_generation(&mut self) {
131 (**self).prepare_generation();
132 }
133
134 fn commit_generation(&self, root: &GreenNode<L>) {
135 (**self).commit_generation(root);
136 }
137}