use std::ops::ControlFlow;
use php_ast::owned::visitor::{walk_owned_block, walk_owned_expr, walk_owned_stmt, OwnedVisitor};
use php_ast::owned::{Block, Expr, Stmt};
pub const STACK_SIZE: usize = 16 * 1024 * 1024;
const RED_ZONE: usize = 512 * 1024;
const SEGMENT_SIZE: usize = 8 * 1024 * 1024;
const PHASE_RED_ZONE: usize = 4 * 1024 * 1024;
const PHASE_SEGMENT_SIZE: usize = 32 * 1024 * 1024;
#[inline]
pub fn ensure_stack<R>(f: impl FnOnce() -> R) -> R {
grow(RED_ZONE, SEGMENT_SIZE, f)
}
#[inline]
pub fn ensure_phase_stack<R>(f: impl FnOnce() -> R) -> R {
grow(PHASE_RED_ZONE, PHASE_SEGMENT_SIZE, f)
}
pub struct GuardedParse(Option<php_rs_parser::ParseResult>);
impl std::ops::Deref for GuardedParse {
type Target = php_rs_parser::ParseResult;
fn deref(&self) -> &Self::Target {
self.0.as_ref().expect("present until dropped")
}
}
impl Drop for GuardedParse {
fn drop(&mut self) {
let parsed = self.0.take();
ensure_phase_stack(|| drop(parsed));
}
}
pub fn parse_versioned(source: &str, version: php_rs_parser::PhpVersion) -> GuardedParse {
GuardedParse(Some(ensure_phase_stack(|| {
php_rs_parser::parse_versioned(source, version)
})))
}
pub fn parse(source: &str) -> GuardedParse {
GuardedParse(Some(ensure_phase_stack(|| php_rs_parser::parse(source))))
}
#[cfg(not(target_arch = "wasm32"))]
fn grow<R>(red_zone: usize, segment: usize, f: impl FnOnce() -> R) -> R {
stacker::maybe_grow(red_zone, segment, f)
}
#[cfg(target_arch = "wasm32")]
fn grow<R>(_red_zone: usize, _segment: usize, f: impl FnOnce() -> R) -> R {
f()
}
pub fn walk_expr<V: OwnedVisitor + ?Sized>(visitor: &mut V, expr: &Expr) -> ControlFlow<()> {
ensure_stack(|| walk_owned_expr(visitor, expr))
}
pub fn walk_stmt<V: OwnedVisitor + ?Sized>(visitor: &mut V, stmt: &Stmt) -> ControlFlow<()> {
ensure_stack(|| walk_owned_stmt(visitor, stmt))
}
pub fn walk_block<V: OwnedVisitor + ?Sized>(visitor: &mut V, block: &Block) -> ControlFlow<()> {
ensure_stack(|| walk_owned_block(visitor, block))
}