Skip to main content

php_rs_parser/
lib.rs

1//! Fast, fault-tolerant PHP parser that produces a fully typed AST.
2//!
3//! This crate parses PHP source code (PHP 8.0–8.5) into a [`php_ast::Program`]
4//! tree, recovering from syntax errors so that downstream tools always receive
5//! a complete AST.
6//!
7//! # Quick start
8//!
9//! ```
10//! let arena = bumpalo::Bump::new();
11//! let result = php_rs_parser::parse(&arena, "<?php echo 'hello';");
12//! assert!(result.errors.is_empty());
13//! ```
14//!
15//! # Version-aware parsing
16//!
17//! Use [`parse_versioned`] to target a specific PHP version. Syntax that
18//! requires a higher version is still parsed into the AST, but a
19//! [`diagnostics::ParseError::VersionTooLow`] diagnostic is emitted.
20//!
21//! ```
22//! let arena = bumpalo::Bump::new();
23//! let result = php_rs_parser::parse_versioned(
24//!     &arena,
25//!     "<?php enum Status { case Active; }",
26//!     php_rs_parser::PhpVersion::Php80,
27//! );
28//! assert!(!result.errors.is_empty()); // enums require PHP 8.1
29//! ```
30
31pub mod diagnostics;
32pub(crate) mod expr;
33pub mod instrument;
34pub(crate) mod interpolation;
35pub(crate) mod parser;
36pub mod phpdoc;
37pub(crate) mod precedence;
38pub mod source_map;
39pub(crate) mod stmt;
40pub mod version;
41
42use diagnostics::ParseError;
43use php_ast::{Comment, Program};
44use source_map::SourceMap;
45pub use version::PhpVersion;
46
47/// The result of parsing a PHP source string.
48pub struct ParseResult<'arena, 'src> {
49    /// The original source text. Useful for extracting text from spans
50    /// via `&result.source[span.start as usize..span.end as usize]`.
51    pub source: &'src str,
52    /// The parsed AST. Always produced, even when errors are present.
53    pub program: Program<'arena, 'src>,
54    /// All comments found in the source, in source order.
55    /// Comments are not attached to AST nodes; callers can map them by span.
56    pub comments: Vec<Comment<'src>>,
57    /// Parse errors and diagnostics. Empty on a successful parse.
58    pub errors: Vec<ParseError>,
59    /// Pre-computed line index for resolving byte offsets in [`Span`](php_ast::Span)
60    /// to line/column positions. Use [`SourceMap::offset_to_line_col`] or
61    /// [`SourceMap::span_to_line_col`] to convert.
62    pub source_map: SourceMap,
63}
64
65/// Parse PHP `source` using the latest supported PHP version (currently 8.5).
66///
67/// The `arena` is used for all AST allocations, giving callers control over
68/// memory lifetime. The returned [`ParseResult`] borrows from both the arena
69/// and the source string.
70pub fn parse<'arena, 'src>(
71    arena: &'arena bumpalo::Bump,
72    source: &'src str,
73) -> ParseResult<'arena, 'src> {
74    let mut parser = parser::Parser::new(arena, source);
75    let program = parser.parse_program();
76    ParseResult {
77        source,
78        program,
79        comments: parser.take_comments(),
80        errors: parser.into_errors(),
81        source_map: SourceMap::new(source),
82    }
83}
84
85/// Parse `source` targeting the given PHP `version`.
86///
87/// Syntax that requires a higher version than `version` is still parsed and
88/// included in the AST, but a [`diagnostics::ParseError::VersionTooLow`] error
89/// is also emitted so callers can report it to the user.
90pub fn parse_versioned<'arena, 'src>(
91    arena: &'arena bumpalo::Bump,
92    source: &'src str,
93    version: PhpVersion,
94) -> ParseResult<'arena, 'src> {
95    let mut parser = parser::Parser::with_version(arena, source, version);
96    let program = parser.parse_program();
97    ParseResult {
98        source,
99        program,
100        comments: parser.take_comments(),
101        errors: parser.into_errors(),
102        source_map: SourceMap::new(source),
103    }
104}