Reduce size of AST.

This commit is contained in:
Stephen Chung 2023-02-21 17:52:11 +08:00
parent b371c524ae
commit a8be9c4d64
2 changed files with 48 additions and 26 deletions

View File

@ -23,9 +23,9 @@ pub struct AST {
source: Option<ImmutableString>, source: Option<ImmutableString>,
/// [`AST`] documentation. /// [`AST`] documentation.
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: Option<crate::SmartString>, doc: Option<Box<crate::SmartString>>,
/// Global statements. /// Global statements.
body: StmtBlock, body: Option<Box<StmtBlock>>,
/// Script-defined functions. /// Script-defined functions.
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
lib: crate::SharedModule, lib: crate::SharedModule,
@ -54,7 +54,14 @@ impl fmt::Debug for AST {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
fp.field("resolver", &self.resolver); fp.field("resolver", &self.resolver);
fp.field("body", &self.body.as_slice()); fp.field(
"body",
&self
.body
.as_deref()
.map(|b| b.as_slice())
.unwrap_or_default(),
);
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
for (.., fn_def) in self.lib.iter_script_fn() { for (.., fn_def) in self.lib.iter_script_fn() {
@ -75,11 +82,13 @@ impl AST {
statements: impl IntoIterator<Item = Stmt>, statements: impl IntoIterator<Item = Stmt>,
#[cfg(not(feature = "no_function"))] functions: impl Into<crate::SharedModule>, #[cfg(not(feature = "no_function"))] functions: impl Into<crate::SharedModule>,
) -> Self { ) -> Self {
let stmt = StmtBlock::new(statements, Position::NONE, Position::NONE);
Self { Self {
source: None, source: None,
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: crate::SmartString::new_const(), doc: crate::SmartString::new_const(),
body: StmtBlock::new(statements, Position::NONE, Position::NONE), body: (!stmt.is_empty()).then(|| stmt.into()),
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
lib: functions.into(), lib: functions.into(),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -95,11 +104,13 @@ impl AST {
statements: impl IntoIterator<Item = Stmt>, statements: impl IntoIterator<Item = Stmt>,
#[cfg(not(feature = "no_function"))] functions: impl Into<crate::SharedModule>, #[cfg(not(feature = "no_function"))] functions: impl Into<crate::SharedModule>,
) -> Self { ) -> Self {
let stmt = StmtBlock::new(statements, Position::NONE, Position::NONE);
Self { Self {
source: None, source: None,
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: None, doc: None,
body: StmtBlock::new(statements, Position::NONE, Position::NONE), body: (!stmt.is_empty()).then(|| stmt.into()),
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
lib: functions.into(), lib: functions.into(),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -149,7 +160,7 @@ impl AST {
source: None, source: None,
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: None, doc: None,
body: StmtBlock::NONE, body: None,
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
lib: crate::Module::new().into(), lib: crate::Module::new().into(),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -220,7 +231,7 @@ impl AST {
#[must_use] #[must_use]
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) fn doc_mut(&mut self) -> Option<&mut crate::SmartString> { pub(crate) fn doc_mut(&mut self) -> Option<&mut crate::SmartString> {
self.doc.as_mut() self.doc.as_deref_mut()
} }
/// Set the documentation. /// Set the documentation.
/// ///
@ -233,7 +244,7 @@ impl AST {
if doc.is_empty() { if doc.is_empty() {
self.doc = None; self.doc = None;
} else { } else {
self.doc = Some(doc); self.doc = Some(doc.into());
} }
} }
/// Get the statements. /// Get the statements.
@ -249,14 +260,20 @@ impl AST {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn statements(&self) -> &[Stmt] { pub fn statements(&self) -> &[Stmt] {
self.body.statements() self.body
.as_deref()
.map(StmtBlock::statements)
.unwrap_or_default()
} }
/// Extract the statements. /// Extract the statements.
#[allow(dead_code)] #[allow(dead_code)]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn take_statements(&mut self) -> StmtBlockContainer { pub(crate) fn take_statements(&mut self) -> StmtBlockContainer {
self.body.take_statements() self.body
.as_deref_mut()
.map(StmtBlock::take_statements)
.unwrap_or_default()
} }
/// Does this [`AST`] contain script-defined functions? /// Does this [`AST`] contain script-defined functions?
/// ///
@ -350,7 +367,7 @@ impl AST {
source: self.source.clone(), source: self.source.clone(),
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
doc: self.doc.clone(), doc: self.doc.clone(),
body: StmtBlock::NONE, body: None,
lib: lib.into(), lib: lib.into(),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
resolver: self.resolver.clone(), resolver: self.resolver.clone(),
@ -548,15 +565,15 @@ impl AST {
other: &Self, other: &Self,
_filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool, _filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
) -> Self { ) -> Self {
let merged = match (self.body.is_empty(), other.body.is_empty()) { let merged = match (&self.body, &other.body) {
(false, false) => { (Some(body), Some(other)) => {
let mut body = self.body.clone(); let mut body = body.as_ref().clone();
body.extend(other.body.iter().cloned()); body.extend(other.iter().cloned());
body body
} }
(false, true) => self.body.clone(), (Some(body), None) => body.as_ref().clone(),
(true, false) => other.body.clone(), (None, Some(body)) => body.as_ref().clone(),
(true, true) => StmtBlock::NONE, (None, None) => StmtBlock::NONE,
}; };
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
@ -698,7 +715,12 @@ impl AST {
} }
} }
self.body.extend(other.body.into_iter()); match (&mut self.body, other.body) {
(Some(body), Some(other)) => body.extend(other.into_iter()),
(Some(_), None) => (),
(None, body @ Some(_)) => self.body = body,
(None, None) => (),
}
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
if !other.lib.is_empty() { if !other.lib.is_empty() {
@ -795,7 +817,7 @@ impl AST {
/// Clear all statements in the [`AST`], leaving only function definitions. /// Clear all statements in the [`AST`], leaving only function definitions.
#[inline(always)] #[inline(always)]
pub fn clear_statements(&mut self) -> &mut Self { pub fn clear_statements(&mut self) -> &mut Self {
self.body = StmtBlock::NONE; self.body = None;
self self
} }
/// Extract all top-level literal constant and/or variable definitions. /// Extract all top-level literal constant and/or variable definitions.

View File

@ -89,21 +89,21 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: None, doc: "", resolver: None, body: [Expr(123 @ 1:53)] }"# r#"AST { source: None, doc: None, resolver: None, body: [Expr(123 @ 1:53)] }"#
); );
let ast = engine.compile("const DECISION = false; if DECISION { 42 } else { 123 }")?; let ast = engine.compile("const DECISION = false; if DECISION { 42 } else { 123 }")?;
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: None, doc: "", resolver: None, body: [Var(("DECISION" @ 1:7, false @ 1:18, None), CONSTANT, 1:1), Expr(123 @ 1:51)] }"# r#"AST { source: None, doc: None, resolver: None, body: [Var(("DECISION" @ 1:7, false @ 1:18, None), CONSTANT, 1:1), Expr(123 @ 1:51)] }"#
); );
let ast = engine.compile("if 1 == 2 { 42 }")?; let ast = engine.compile("if 1 == 2 { 42 }")?;
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: None, doc: "", resolver: None, body: [] }"# r#"AST { source: None, doc: None, resolver: None, body: [] }"#
); );
engine.set_optimization_level(OptimizationLevel::Full); engine.set_optimization_level(OptimizationLevel::Full);
@ -112,14 +112,14 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: None, doc: "", resolver: None, body: [Expr(42 @ 1:1)] }"# r#"AST { source: None, doc: None, resolver: None, body: [Expr(42 @ 1:1)] }"#
); );
let ast = engine.compile("NUMBER")?; let ast = engine.compile("NUMBER")?;
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: None, doc: "", resolver: None, body: [Expr(Variable(NUMBER) @ 1:1)] }"# r#"AST { source: None, doc: None, resolver: None, body: [Expr(Variable(NUMBER) @ 1:1)] }"#
); );
let mut module = Module::new(); let mut module = Module::new();
@ -131,7 +131,7 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
assert_eq!( assert_eq!(
format!("{ast:?}"), format!("{ast:?}"),
r#"AST { source: None, doc: "", resolver: None, body: [Expr(42 @ 1:1)] }"# r#"AST { source: None, doc: None, resolver: None, body: [Expr(42 @ 1:1)] }"#
); );
Ok(()) Ok(())