Change AST to struct.

This commit is contained in:
Stephen Chung 2020-12-12 15:57:55 +08:00
parent 40b6a014ae
commit dbdb8f43b7
2 changed files with 50 additions and 32 deletions

View File

@ -111,30 +111,39 @@ impl fmt::Display for ScriptFnDef {
///
/// Currently, [`AST`] is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
#[derive(Debug, Clone)]
pub struct AST(
pub struct AST {
/// Global statements.
Vec<Stmt>,
statements: Vec<Stmt>,
/// Script-defined functions.
Shared<Module>,
);
functions: Shared<Module>,
}
impl Default for AST {
fn default() -> Self {
Self(Vec::with_capacity(16), Default::default())
Self {
statements: Vec::with_capacity(16),
functions: Default::default(),
}
}
}
impl AST {
/// Create a new [`AST`].
#[inline(always)]
pub fn new(statements: impl IntoIterator<Item = Stmt>, lib: impl Into<Shared<Module>>) -> Self {
Self(statements.into_iter().collect(), lib.into())
pub fn new(
statements: impl IntoIterator<Item = Stmt>,
functions: impl Into<Shared<Module>>,
) -> Self {
Self {
statements: statements.into_iter().collect(),
functions: functions.into(),
}
}
/// Get the statements.
#[cfg(not(feature = "internals"))]
#[inline(always)]
pub(crate) fn statements(&self) -> &[Stmt] {
&self.0
&self.statements
}
/// _(INTERNALS)_ Get the statements.
/// Exported under the `internals` feature only.
@ -142,26 +151,26 @@ impl AST {
#[deprecated(note = "this method is volatile and may change")]
#[inline(always)]
pub fn statements(&self) -> &[Stmt] {
&self.0
&self.statements
}
/// Get a mutable reference to the statements.
#[cfg(not(feature = "no_optimize"))]
#[inline(always)]
pub(crate) fn statements_mut(&mut self) -> &mut Vec<Stmt> {
&mut self.0
&mut self.statements
}
/// Get the internal shared [`Module`] containing all script-defined functions.
#[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "no_function"))]
#[inline(always)]
pub(crate) fn shared_lib(&self) -> Shared<Module> {
self.1.clone()
self.functions.clone()
}
/// Get the internal [`Module`] containing all script-defined functions.
#[cfg(not(feature = "internals"))]
#[inline(always)]
pub(crate) fn lib(&self) -> &Module {
&self.1
&self.functions
}
/// _(INTERNALS)_ Get the internal [`Module`] containing all script-defined functions.
/// Exported under the `internals` feature only.
@ -169,7 +178,7 @@ impl AST {
#[deprecated(note = "this method is volatile and may change")]
#[inline(always)]
pub fn lib(&self) -> &Module {
&self.1
&self.functions
}
/// Clone the [`AST`]'s functions into a new [`AST`].
/// No statements are cloned.
@ -191,14 +200,20 @@ impl AST {
mut filter: impl FnMut(FnNamespace, FnAccess, bool, &str, usize) -> bool,
) -> Self {
let mut functions: Module = Default::default();
functions.merge_filtered(&self.1, &mut filter);
Self(Default::default(), functions.into())
functions.merge_filtered(&self.functions, &mut filter);
Self {
statements: Default::default(),
functions: functions.into(),
}
}
/// Clone the [`AST`]'s script statements into a new [`AST`].
/// No functions are cloned.
#[inline(always)]
pub fn clone_statements_only(&self) -> Self {
Self(self.0.clone(), Default::default())
Self {
statements: self.statements.clone(),
functions: Default::default(),
}
}
/// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged, version
/// is returned.
@ -363,21 +378,24 @@ impl AST {
other: &Self,
mut filter: impl FnMut(FnNamespace, FnAccess, bool, &str, usize) -> bool,
) -> Self {
let Self(statements, functions) = self;
let Self {
statements,
functions,
} = self;
let ast = match (statements.is_empty(), other.0.is_empty()) {
let ast = match (statements.is_empty(), other.statements.is_empty()) {
(false, false) => {
let mut statements = statements.clone();
statements.extend(other.0.iter().cloned());
statements.extend(other.statements.iter().cloned());
statements
}
(false, true) => statements.clone(),
(true, false) => other.0.clone(),
(true, false) => other.statements.clone(),
(true, true) => vec![],
};
let mut functions = functions.as_ref().clone();
functions.merge_filtered(&other.1, &mut filter);
functions.merge_filtered(&other.functions, &mut filter);
Self::new(ast, functions)
}
@ -438,9 +456,9 @@ impl AST {
other: Self,
mut filter: impl FnMut(FnNamespace, FnAccess, bool, &str, usize) -> bool,
) -> &mut Self {
self.0.extend(other.0.into_iter());
if !other.1.is_empty() {
shared_make_mut(&mut self.1).merge_filtered(&other.1, &mut filter);
self.statements.extend(other.statements.into_iter());
if !other.functions.is_empty() {
shared_make_mut(&mut self.functions).merge_filtered(&other.functions, &mut filter);
}
self
}
@ -473,8 +491,8 @@ impl AST {
&mut self,
filter: impl FnMut(FnNamespace, FnAccess, &str, usize) -> bool,
) -> &mut Self {
if !self.1.is_empty() {
shared_make_mut(&mut self.1).retain_script_functions(filter);
if !self.functions.is_empty() {
shared_make_mut(&mut self.functions).retain_script_functions(filter);
}
self
}
@ -484,18 +502,18 @@ impl AST {
pub fn iter_functions<'a>(
&'a self,
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, &ScriptFnDef)> + 'a {
self.1.iter_script_fn()
self.functions.iter_script_fn()
}
/// Clear all function definitions in the [`AST`].
#[cfg(not(feature = "no_function"))]
#[inline(always)]
pub fn clear_functions(&mut self) {
self.1 = Default::default();
self.functions = Default::default();
}
/// Clear all statements in the [`AST`], leaving only function definitions.
#[inline(always)]
pub fn clear_statements(&mut self) {
self.0 = vec![];
self.statements = vec![];
}
}

View File

@ -55,17 +55,17 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
let ast = engine.compile("{ const DECISION = false; if DECISION { 42 } else { 123 } }")?;
assert!(format!("{:?}", ast).starts_with(r#"AST([Block([Const(IdentX { name: "DECISION", pos: 1:9 }, Some(Unit(0:0)), false, 1:3), Expr(IntegerConstant(123, 1:53))], 1:1)]"#));
assert!(format!("{:?}", ast).starts_with(r#"AST { statements: [Block([Const(IdentX { name: "DECISION", pos: 1:9 }, Some(Unit(0:0)), false, 1:3), Expr(IntegerConstant(123, 1:53))], 1:1)]"#));
let ast = engine.compile("if 1 == 2 { 42 }")?;
assert!(format!("{:?}", ast).starts_with("AST([], Module("));
assert!(format!("{:?}", ast).starts_with("AST { statements: [], functions: Module("));
engine.set_optimization_level(OptimizationLevel::Full);
let ast = engine.compile("abs(-42)")?;
assert!(format!("{:?}", ast).starts_with(r"AST([Expr(IntegerConstant(42, 1:1))]"));
assert!(format!("{:?}", ast).starts_with(r"AST { statements: [Expr(IntegerConstant(42, 1:1))]"));
Ok(())
}