Skip to content

Commit

Permalink
parser: return mutable reference into arena instead of owned program
Browse files Browse the repository at this point in the history
  • Loading branch information
valeneiko committed Jan 12, 2025
1 parent 5cd1771 commit a1eed28
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
24 changes: 23 additions & 1 deletion crates/oxc_allocator/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::Allocator;
/// being called to guarantee soundness.
pub struct Box<'alloc, T: ?Sized>(NonNull<T>, PhantomData<(&'alloc (), T)>);

impl<T> Box<'_, T> {
impl<'a, T> Box<'a, T> {
/// Take ownership of the value stored in this [`Box`], consuming the box in
/// the process.
///
Expand All @@ -54,6 +54,28 @@ impl<T> Box<'_, T> {
// one just allocated from a Bump.
unsafe { ptr::read(self.0.as_ptr()) }
}

/// Consumes and leaks the `Box`, returning a mutable reference,
/// `&'a mut T`.
///
/// ## Example
/// ```
/// use oxc_allocator::{Allocator, Box};
///
/// let arena = Allocator::default();
///
/// // Put `5` into the arena and on the heap.
/// let boxed: Box<i32> = Box::new_in(5, &arena);
/// // Get a reference to the underlying value within the `arena`. `boxed` has been consumed.
/// let i = boxed.unbox();
///
/// assert_eq!(i, 5);
/// ```
#[inline]
pub fn leak(mut b: Self) -> &'a mut T {
// SAFETY: reference obtained from value stored in the box will always be valid
unsafe { b.0.as_mut() }
}
}

impl<T> Box<'_, T> {
Expand Down
16 changes: 8 additions & 8 deletions crates/oxc_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ pub struct ParserReturn<'a> {
///
/// To ensure a valid AST, check that [`errors`](ParserReturn::errors) is empty. Then, run
/// semantic analysis with syntax error checking enabled.
pub program: Program<'a>,
pub program: &'a mut Program<'a>,

/// See <https://tc39.es/ecma262/#sec-abstract-module-records>
pub module_record: ModuleRecord<'a>,
Expand Down Expand Up @@ -411,19 +411,19 @@ impl<'a> ParserImpl<'a> {
/// Recoverable errors are stored inside `errors`.
#[inline]
pub fn parse(mut self) -> ParserReturn<'a> {
let (mut program, panicked) = match self.parse_program() {
let (program, panicked) = match self.parse_program() {
Ok(program) => (program, false),
Err(error) => {
self.error(self.overlong_error().unwrap_or(error));
let program = self.ast.program(
let program = ArenaBox::leak(self.ast.alloc_program(
Span::default(),
self.source_type,
self.source_text,
self.ast.vec(),
None,
self.ast.vec(),
self.ast.vec(),
);
));
(program, true)
}
};
Expand Down Expand Up @@ -483,7 +483,7 @@ impl<'a> ParserImpl<'a> {
}

#[allow(clippy::cast_possible_truncation)]
fn parse_program(&mut self) -> Result<Program<'a>> {
fn parse_program(&mut self) -> Result<&'a mut Program<'a>> {
// initialize cur_token and prev_token by moving onto the first token
self.bump_any();

Expand All @@ -493,15 +493,15 @@ impl<'a> ParserImpl<'a> {

let span = Span::new(0, self.source_text.len() as u32);
let comments = self.ast.vec_from_iter(self.lexer.trivia_builder.comments.iter().copied());
Ok(self.ast.program(
Ok(ArenaBox::leak(self.ast.alloc_program(
span,
self.source_type,
self.source_text,
comments,
hashbang,
directives,
statements,
))
)))
}

fn default_context(source_type: SourceType, options: ParseOptions) -> Context {
Expand Down Expand Up @@ -679,7 +679,7 @@ mod test {
let source_type = SourceType::default();
let source = "#!/usr/bin/node\n;";
let ret = Parser::new(&allocator, source, source_type).parse();
assert_eq!(ret.program.hashbang.unwrap().value.as_str(), "/usr/bin/node");
assert_eq!(ret.program.hashbang.as_ref().unwrap().value.as_str(), "/usr/bin/node");
}

#[test]
Expand Down

0 comments on commit a1eed28

Please sign in to comment.