MCPcopy Create free account
hub / github.com/PHPantom-dev/phpantom_lsp / with_parsed_program

Function with_parsed_program

src/parser/mod.rs:748–819  ·  view source on GitHub ↗

Parse `content` with the mago-syntax parser and pass the resulting `Program` (plus the content string) to `f`. Handles the boilerplate that every parse entry-point needs: allocating a `Bump` arena, creating a `FileId`, calling `parse_file_content`, and wrapping the whole thing in `catch_unwind` so that a parser panic doesn't crash the LSP server. On panic the error is logged (using `method_name`

(
    content: &str,
    method_name: &str,
    f: impl FnOnce(&Program<'_>, &str) -> T,
)

Source from the content-addressed store, hash-verified

746/// the previously parsed `Program` is reused — no allocation or
747/// parsing occurs.
748pub(crate) fn with_parsed_program<T: Default>(
749 content: &str,
750 method_name: &str,
751 f: impl FnOnce(&Program<'_>, &str) -> T,
752) -> T {
753 // ── Fast path: check the thread-local cache ─────────────────
754 // 0 = miss, 1 = content matches but not yet parsed, 2 = ready
755 let cache_state: u8 = PARSE_CACHE.with(|cell| {
756 let borrow = cell.borrow();
757 match borrow.as_ref() {
758 Some(e) if e.content == content => {
759 if e.program_ptr.is_some() {
760 2
761 } else {
762 1
763 }
764 }
765 _ => 0,
766 }
767 });
768
769 // Lazily parse on first access and populate the cache entry.
770 if cache_state == 1 {
771 PARSE_CACHE.with(|cell| {
772 let mut borrow = cell.borrow_mut();
773 let entry = borrow.as_mut().unwrap();
774 let arena = bumpalo::Bump::new();
775 let file_id = mago_database::file::FileId::new("input.php");
776 // SAFETY: `program` borrows from `arena` and `entry.content`.
777 // The arena is moved into `entry.arena` immediately after
778 // extracting the raw pointer — the heap-allocated chunks do
779 // not move, so the pointer stays valid. `entry.content` lives
780 // inside the `RefCell` until the guard is dropped.
781 let program = mago_syntax::parser::parse_file_content(&arena, file_id, &entry.content);
782 let program_ptr: *const () = (program as *const Program<'_>).cast();
783 entry.program_ptr = Some(program_ptr);
784 entry.arena = Some(arena);
785 });
786 }
787
788 if cache_state >= 1 {
789 return PARSE_CACHE.with(|cell| {
790 let borrow = cell.borrow();
791 let entry = borrow.as_ref().unwrap();
792 // SAFETY: `program_ptr` was created from a valid `&Program`
793 // whose backing arena and content string are still alive
794 // inside `entry`. We hold a `Ref` borrow on the `RefCell`,
795 // so the entry cannot be mutated or dropped while we use
796 // the reference.
797 let program: &Program<'_> =
798 unsafe { &*(entry.program_ptr.unwrap().cast::<Program<'_>>()) };
799 f(program, &entry.content)
800 });
801 }
802
803 // ── Slow path: parse from scratch ───────────────────────────
804 let content_owned = content.to_string();
805 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {

Calls 1

unwrapMethod · 0.45

Tested by 3

collect_from_functionFunction · 0.68
collect_from_methodFunction · 0.68