mirror of https://github.com/boa-dev/boa.git
0x7D2B
4 years ago
committed by
GitHub
17 changed files with 738 additions and 779 deletions
@ -1,142 +0,0 @@
|
||||
use crate::{ |
||||
environment::lexical_environment::VariableScope, |
||||
exec::Executable, |
||||
gc::{Finalize, Trace}, |
||||
syntax::ast::node::{join_nodes, Identifier, Node}, |
||||
Context, Result, Value, |
||||
}; |
||||
use std::fmt; |
||||
|
||||
#[cfg(feature = "deser")] |
||||
use serde::{Deserialize, Serialize}; |
||||
|
||||
/// The `const` statements are block-scoped, much like variables defined using the `let`
|
||||
/// keyword.
|
||||
///
|
||||
/// This declaration creates a constant whose scope can be either global or local to the block
|
||||
/// in which it is declared. Global constants do not become properties of the window object,
|
||||
/// unlike var variables.
|
||||
///
|
||||
/// An initializer for a constant is required. You must specify its value in the same statement
|
||||
/// in which it's declared. (This makes sense, given that it can't be changed later.)
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
||||
/// [identifier]: https://developer.mozilla.org/en-US/docs/Glossary/identifier
|
||||
/// [expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions
|
||||
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))] |
||||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] |
||||
pub struct ConstDeclList { |
||||
#[cfg_attr(feature = "deser", serde(flatten))] |
||||
list: Box<[ConstDecl]>, |
||||
} |
||||
|
||||
impl Executable for ConstDeclList { |
||||
fn run(&self, context: &mut Context) -> Result<Value> { |
||||
for decl in self.as_ref() { |
||||
let val = if let Some(init) = decl.init() { |
||||
init.run(context)? |
||||
} else { |
||||
return context.throw_syntax_error("missing = in const declaration"); |
||||
}; |
||||
context |
||||
.realm_mut() |
||||
.environment |
||||
.create_immutable_binding(decl.name().to_owned(), false, VariableScope::Block) |
||||
.map_err(|e| e.to_error(context))?; |
||||
|
||||
context |
||||
.realm_mut() |
||||
.environment |
||||
.initialize_binding(decl.name(), val) |
||||
.map_err(|e| e.to_error(context))?; |
||||
} |
||||
Ok(Value::undefined()) |
||||
} |
||||
} |
||||
|
||||
impl<T> From<T> for ConstDeclList |
||||
where |
||||
T: Into<Box<[ConstDecl]>>, |
||||
{ |
||||
fn from(list: T) -> Self { |
||||
Self { list: list.into() } |
||||
} |
||||
} |
||||
|
||||
impl From<ConstDecl> for ConstDeclList { |
||||
fn from(decl: ConstDecl) -> Self { |
||||
Self { |
||||
list: Box::new([decl]), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl AsRef<[ConstDecl]> for ConstDeclList { |
||||
fn as_ref(&self) -> &[ConstDecl] { |
||||
&self.list |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for ConstDeclList { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
if !self.list.is_empty() { |
||||
write!(f, "const ")?; |
||||
join_nodes(f, &self.list) |
||||
} else { |
||||
Ok(()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<ConstDeclList> for Node { |
||||
fn from(list: ConstDeclList) -> Self { |
||||
Self::ConstDeclList(list) |
||||
} |
||||
} |
||||
|
||||
/// Individual constant declaration.
|
||||
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))] |
||||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] |
||||
pub struct ConstDecl { |
||||
name: Identifier, |
||||
init: Option<Node>, |
||||
} |
||||
|
||||
impl fmt::Display for ConstDecl { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
fmt::Display::fmt(&self.name, f)?; |
||||
if let Some(ref init) = self.init { |
||||
write!(f, " = {}", init)?; |
||||
} |
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
impl ConstDecl { |
||||
/// Creates a new variable declaration.
|
||||
pub(in crate::syntax) fn new<N, I>(name: N, init: Option<I>) -> Self |
||||
where |
||||
N: Into<Identifier>, |
||||
I: Into<Node>, |
||||
{ |
||||
Self { |
||||
name: name.into(), |
||||
init: init.map(|n| n.into()), |
||||
} |
||||
} |
||||
|
||||
/// Gets the name of the variable.
|
||||
pub fn name(&self) -> &str { |
||||
self.name.as_ref() |
||||
} |
||||
|
||||
/// Gets the initialization node for the variable, if any.
|
||||
pub fn init(&self) -> &Option<Node> { |
||||
&self.init |
||||
} |
||||
} |
@ -1,139 +0,0 @@
|
||||
use crate::{ |
||||
environment::lexical_environment::VariableScope, |
||||
exec::Executable, |
||||
gc::{Finalize, Trace}, |
||||
syntax::ast::node::{join_nodes, Identifier, Node}, |
||||
Context, Result, Value, |
||||
}; |
||||
use std::fmt; |
||||
|
||||
#[cfg(feature = "deser")] |
||||
use serde::{Deserialize, Serialize}; |
||||
|
||||
/// The `let` statement declares a block scope local variable, optionally initializing it to a
|
||||
/// value.
|
||||
///
|
||||
///
|
||||
/// `let` allows you to declare variables that are limited to a scope of a block statement, or
|
||||
/// expression on which it is used, unlike the `var` keyword, which defines a variable
|
||||
/// globally, or locally to an entire function regardless of block scope.
|
||||
///
|
||||
/// Just like const the `let` does not create properties of the window object when declared
|
||||
/// globally (in the top-most scope).
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
|
||||
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))] |
||||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] |
||||
pub struct LetDeclList { |
||||
#[cfg_attr(feature = "deser", serde(flatten))] |
||||
list: Box<[LetDecl]>, |
||||
} |
||||
|
||||
impl Executable for LetDeclList { |
||||
fn run(&self, context: &mut Context) -> Result<Value> { |
||||
for var in self.as_ref() { |
||||
let val = match var.init() { |
||||
Some(v) => v.run(context)?, |
||||
None => Value::undefined(), |
||||
}; |
||||
context |
||||
.realm_mut() |
||||
.environment |
||||
.create_mutable_binding(var.name().to_owned(), false, VariableScope::Block) |
||||
.map_err(|e| e.to_error(context))?; |
||||
context |
||||
.realm_mut() |
||||
.environment |
||||
.initialize_binding(var.name(), val) |
||||
.map_err(|e| e.to_error(context))?; |
||||
} |
||||
Ok(Value::undefined()) |
||||
} |
||||
} |
||||
|
||||
impl<T> From<T> for LetDeclList |
||||
where |
||||
T: Into<Box<[LetDecl]>>, |
||||
{ |
||||
fn from(list: T) -> Self { |
||||
Self { list: list.into() } |
||||
} |
||||
} |
||||
|
||||
impl From<LetDecl> for LetDeclList { |
||||
fn from(decl: LetDecl) -> Self { |
||||
Self { |
||||
list: Box::new([decl]), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl AsRef<[LetDecl]> for LetDeclList { |
||||
fn as_ref(&self) -> &[LetDecl] { |
||||
&self.list |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for LetDeclList { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
if !self.list.is_empty() { |
||||
write!(f, "let ")?; |
||||
join_nodes(f, &self.list) |
||||
} else { |
||||
Ok(()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<LetDeclList> for Node { |
||||
fn from(list: LetDeclList) -> Self { |
||||
Self::LetDeclList(list) |
||||
} |
||||
} |
||||
|
||||
/// Individual constant declaration.
|
||||
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))] |
||||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] |
||||
pub struct LetDecl { |
||||
name: Identifier, |
||||
init: Option<Node>, |
||||
} |
||||
|
||||
impl fmt::Display for LetDecl { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
fmt::Display::fmt(&self.name, f)?; |
||||
if let Some(ref init) = self.init { |
||||
write!(f, " = {}", init)?; |
||||
} |
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
impl LetDecl { |
||||
/// Creates a new variable declaration.
|
||||
pub(in crate::syntax) fn new<N, I>(name: N, init: I) -> Self |
||||
where |
||||
N: Into<Identifier>, |
||||
I: Into<Option<Node>>, |
||||
{ |
||||
Self { |
||||
name: name.into(), |
||||
init: init.into(), |
||||
} |
||||
} |
||||
|
||||
/// Gets the name of the variable.
|
||||
pub fn name(&self) -> &str { |
||||
self.name.as_ref() |
||||
} |
||||
|
||||
/// Gets the initialization node for the variable, if any.
|
||||
pub fn init(&self) -> Option<&Node> { |
||||
self.init.as_ref() |
||||
} |
||||
} |
@ -1,24 +1,232 @@
|
||||
//! Declaration nodes
|
||||
use crate::{ |
||||
environment::lexical_environment::VariableScope, |
||||
exec::Executable, |
||||
gc::{Finalize, Trace}, |
||||
syntax::ast::node::{join_nodes, Identifier, Node}, |
||||
Context, Result, Value, |
||||
}; |
||||
use std::fmt; |
||||
|
||||
#[cfg(feature = "deser")] |
||||
use serde::{Deserialize, Serialize}; |
||||
|
||||
pub mod arrow_function_decl; |
||||
pub mod async_function_decl; |
||||
pub mod async_function_expr; |
||||
pub mod const_decl_list; |
||||
pub mod function_decl; |
||||
pub mod function_expr; |
||||
pub mod let_decl_list; |
||||
pub mod var_decl_list; |
||||
|
||||
pub use self::{ |
||||
arrow_function_decl::ArrowFunctionDecl, |
||||
async_function_decl::AsyncFunctionDecl, |
||||
async_function_expr::AsyncFunctionExpr, |
||||
const_decl_list::{ConstDecl, ConstDeclList}, |
||||
function_decl::FunctionDecl, |
||||
arrow_function_decl::ArrowFunctionDecl, async_function_decl::AsyncFunctionDecl, |
||||
async_function_expr::AsyncFunctionExpr, function_decl::FunctionDecl, |
||||
function_expr::FunctionExpr, |
||||
let_decl_list::{LetDecl, LetDeclList}, |
||||
var_decl_list::{VarDecl, VarDeclList}, |
||||
}; |
||||
|
||||
#[cfg(test)] |
||||
mod tests; |
||||
|
||||
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))] |
||||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] |
||||
pub enum DeclarationList { |
||||
/// The `const` statements are block-scoped, much like variables defined using the `let`
|
||||
/// keyword.
|
||||
///
|
||||
/// This declaration creates a constant whose scope can be either global or local to the block
|
||||
/// in which it is declared. Global constants do not become properties of the window object,
|
||||
/// unlike var variables.
|
||||
///
|
||||
/// An initializer for a constant is required. You must specify its value in the same statement
|
||||
/// in which it's declared. (This makes sense, given that it can't be changed later.)
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
||||
/// [identifier]: https://developer.mozilla.org/en-US/docs/Glossary/identifier
|
||||
/// [expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions
|
||||
Const(Box<[Declaration]>), |
||||
|
||||
/// The `let` statement declares a block scope local variable, optionally initializing it to a
|
||||
/// value.
|
||||
///
|
||||
///
|
||||
/// `let` allows you to declare variables that are limited to a scope of a block statement, or
|
||||
/// expression on which it is used, unlike the `var` keyword, which defines a variable
|
||||
/// globally, or locally to an entire function regardless of block scope.
|
||||
///
|
||||
/// Just like const the `let` does not create properties of the window object when declared
|
||||
/// globally (in the top-most scope).
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
|
||||
Let(Box<[Declaration]>), |
||||
|
||||
/// The `var` statement declares a variable, optionally initializing it to a value.
|
||||
///
|
||||
/// var declarations, wherever they occur, are processed before any code is executed. This is
|
||||
/// called hoisting, and is discussed further below.
|
||||
///
|
||||
/// The scope of a variable declared with var is its current execution context, which is either
|
||||
/// the enclosing function or, for variables declared outside any function, global. If you
|
||||
/// re-declare a JavaScript variable, it will not lose its value.
|
||||
///
|
||||
/// Assigning a value to an undeclared variable implicitly creates it as a global variable (it
|
||||
/// becomes a property of the global object) when the assignment is executed.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-VariableStatement
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
|
||||
Var(Box<[Declaration]>), |
||||
} |
||||
|
||||
impl Executable for DeclarationList { |
||||
fn run(&self, context: &mut Context) -> Result<Value> { |
||||
for decl in self.as_ref() { |
||||
use DeclarationList::*; |
||||
let val = match decl.init() { |
||||
None if self.is_const() => { |
||||
return context.throw_syntax_error("missing = in const declaration") |
||||
} |
||||
Some(init) => init.run(context)?, |
||||
None => Value::undefined(), |
||||
}; |
||||
|
||||
let environment = &mut context.realm_mut().environment; |
||||
|
||||
if self.is_var() && environment.has_binding(decl.name()) { |
||||
if decl.init().is_some() { |
||||
environment |
||||
.set_mutable_binding(decl.name(), val, true) |
||||
.map_err(|e| e.to_error(context))?; |
||||
} |
||||
continue; |
||||
} |
||||
match &self { |
||||
Const(_) => environment |
||||
.create_immutable_binding(decl.name().to_owned(), false, VariableScope::Block) |
||||
.map_err(|e| e.to_error(context))?, |
||||
Let(_) => environment |
||||
.create_mutable_binding(decl.name().to_owned(), false, VariableScope::Block) |
||||
.map_err(|e| e.to_error(context))?, |
||||
Var(_) => environment |
||||
.create_mutable_binding(decl.name().to_owned(), false, VariableScope::Function) |
||||
.map_err(|e| e.to_error(context))?, |
||||
} |
||||
|
||||
context |
||||
.realm_mut() |
||||
.environment |
||||
.initialize_binding(decl.name(), val) |
||||
.map_err(|e| e.to_error(context))?; |
||||
} |
||||
|
||||
Ok(Value::undefined()) |
||||
} |
||||
} |
||||
|
||||
impl DeclarationList { |
||||
#[allow(dead_code)] |
||||
pub(in crate::syntax) fn is_let(&self) -> bool { |
||||
matches!(self, Self::Let(_)) |
||||
} |
||||
pub(in crate::syntax) fn is_const(&self) -> bool { |
||||
matches!(self, Self::Const(_)) |
||||
} |
||||
pub(in crate::syntax) fn is_var(&self) -> bool { |
||||
matches!(self, Self::Var(_)) |
||||
} |
||||
} |
||||
|
||||
impl AsRef<[Declaration]> for DeclarationList { |
||||
fn as_ref(&self) -> &[Declaration] { |
||||
use DeclarationList::*; |
||||
match self { |
||||
Var(list) | Const(list) | Let(list) => list, |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for DeclarationList { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
if !self.as_ref().is_empty() { |
||||
use DeclarationList::*; |
||||
match &self { |
||||
Let(_) => write!(f, "let ")?, |
||||
Const(_) => write!(f, "const ")?, |
||||
Var(_) => write!(f, "var ")?, |
||||
} |
||||
join_nodes(f, self.as_ref()) |
||||
} else { |
||||
Ok(()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<DeclarationList> for Node { |
||||
fn from(list: DeclarationList) -> Self { |
||||
use DeclarationList::*; |
||||
match &list { |
||||
Let(_) => Node::LetDeclList(list), |
||||
Const(_) => Node::ConstDeclList(list), |
||||
Var(_) => Node::VarDeclList(list), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl Into<Box<[Declaration]>> for Declaration { |
||||
fn into(self) -> Box<[Declaration]> { |
||||
Box::new([self]) |
||||
} |
||||
} |
||||
|
||||
/// Individual declaration.
|
||||
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))] |
||||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] |
||||
pub struct Declaration { |
||||
name: Identifier, |
||||
init: Option<Node>, |
||||
} |
||||
|
||||
impl fmt::Display for Declaration { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
fmt::Display::fmt(&self.name, f)?; |
||||
if let Some(ref init) = self.init { |
||||
write!(f, " = {}", init)?; |
||||
} |
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
impl Declaration { |
||||
/// Creates a new variable declaration.
|
||||
pub(in crate::syntax) fn new<N, I>(name: N, init: I) -> Self |
||||
where |
||||
N: Into<Identifier>, |
||||
I: Into<Option<Node>>, |
||||
{ |
||||
Self { |
||||
name: name.into(), |
||||
init: init.into(), |
||||
} |
||||
} |
||||
|
||||
/// Gets the name of the variable.
|
||||
pub fn name(&self) -> &str { |
||||
self.name.as_ref() |
||||
} |
||||
|
||||
/// Gets the initialization node for the variable, if any.
|
||||
pub fn init(&self) -> Option<&Node> { |
||||
self.init.as_ref() |
||||
} |
||||
} |
||||
|
@ -1,147 +0,0 @@
|
||||
use crate::{ |
||||
environment::lexical_environment::VariableScope, |
||||
exec::Executable, |
||||
gc::{Finalize, Trace}, |
||||
syntax::ast::node::{join_nodes, Identifier, Node}, |
||||
Context, Result, Value, |
||||
}; |
||||
use std::fmt; |
||||
|
||||
#[cfg(feature = "deser")] |
||||
use serde::{Deserialize, Serialize}; |
||||
|
||||
/// The `var` statement declares a variable, optionally initializing it to a value.
|
||||
///
|
||||
/// var declarations, wherever they occur, are processed before any code is executed. This is
|
||||
/// called hoisting, and is discussed further below.
|
||||
///
|
||||
/// The scope of a variable declared with var is its current execution context, which is either
|
||||
/// the enclosing function or, for variables declared outside any function, global. If you
|
||||
/// re-declare a JavaScript variable, it will not lose its value.
|
||||
///
|
||||
/// Assigning a value to an undeclared variable implicitly creates it as a global variable (it
|
||||
/// becomes a property of the global object) when the assignment is executed.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
/// - [MDN documentation][mdn]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#prod-VariableStatement
|
||||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
|
||||
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))] |
||||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] |
||||
pub struct VarDeclList { |
||||
#[cfg_attr(feature = "deser", serde(flatten))] |
||||
vars: Box<[VarDecl]>, |
||||
} |
||||
|
||||
impl Executable for VarDeclList { |
||||
fn run(&self, context: &mut Context) -> Result<Value> { |
||||
for var in self.as_ref() { |
||||
let val = match var.init() { |
||||
Some(v) => v.run(context)?, |
||||
None => Value::undefined(), |
||||
}; |
||||
let environment = &mut context.realm_mut().environment; |
||||
|
||||
if environment.has_binding(var.name()) { |
||||
if var.init().is_some() { |
||||
environment |
||||
.set_mutable_binding(var.name(), val, true) |
||||
.map_err(|e| e.to_error(context))?; |
||||
} |
||||
} else { |
||||
environment |
||||
.create_mutable_binding(var.name().to_owned(), false, VariableScope::Function) |
||||
.map_err(|e| e.to_error(context))?; |
||||
let environment = &mut context.realm_mut().environment; |
||||
environment |
||||
.initialize_binding(var.name(), val) |
||||
.map_err(|e| e.to_error(context))?; |
||||
} |
||||
} |
||||
Ok(Value::undefined()) |
||||
} |
||||
} |
||||
|
||||
impl<T> From<T> for VarDeclList |
||||
where |
||||
T: Into<Box<[VarDecl]>>, |
||||
{ |
||||
fn from(list: T) -> Self { |
||||
Self { vars: list.into() } |
||||
} |
||||
} |
||||
|
||||
impl From<VarDecl> for VarDeclList { |
||||
fn from(decl: VarDecl) -> Self { |
||||
Self { |
||||
vars: Box::new([decl]), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl AsRef<[VarDecl]> for VarDeclList { |
||||
fn as_ref(&self) -> &[VarDecl] { |
||||
&self.vars |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for VarDeclList { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
if !self.vars.is_empty() { |
||||
write!(f, "var ")?; |
||||
join_nodes(f, &self.vars) |
||||
} else { |
||||
Ok(()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<VarDeclList> for Node { |
||||
fn from(list: VarDeclList) -> Self { |
||||
Self::VarDeclList(list) |
||||
} |
||||
} |
||||
|
||||
/// Individual variable declaration.
|
||||
#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))] |
||||
#[derive(Clone, Debug, Trace, Finalize, PartialEq)] |
||||
pub struct VarDecl { |
||||
name: Identifier, |
||||
init: Option<Node>, |
||||
} |
||||
|
||||
impl fmt::Display for VarDecl { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
fmt::Display::fmt(&self.name, f)?; |
||||
if let Some(ref init) = self.init { |
||||
write!(f, " = {}", init)?; |
||||
} |
||||
Ok(()) |
||||
} |
||||
} |
||||
|
||||
impl VarDecl { |
||||
/// Creates a new variable declaration.
|
||||
pub(in crate::syntax) fn new<N, I>(name: N, init: I) -> Self |
||||
where |
||||
N: Into<Identifier>, |
||||
I: Into<Option<Node>>, |
||||
{ |
||||
Self { |
||||
name: name.into(), |
||||
init: init.into(), |
||||
} |
||||
} |
||||
|
||||
/// Gets the name of the variable.
|
||||
pub fn name(&self) -> &str { |
||||
self.name.as_ref() |
||||
} |
||||
|
||||
/// Gets the initialization node for the variable, if any.
|
||||
pub fn init(&self) -> Option<&Node> { |
||||
self.init.as_ref() |
||||
} |
||||
} |
Loading…
Reference in new issue