use super::*;
use crate::allocator::AstArena;
use crate::location::Position;
use std::fmt;
use std::marker::PhantomData;
use std::ptr::NonNull;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StatementTag {
Block,
Assign,
CompoundAssign,
Break,
Continue,
Class,
Expression,
NumericFor,
GenericFor,
FunctionDeclaration,
If,
LocalFunction,
Local,
TypeAlias,
TypeFunction,
DeclareGlobal,
DeclareFunction,
DeclareExternType,
Repeat,
Return,
While,
Error,
}
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct StatementHeader<'ast> {
pub tag: StatementTag,
pub location: Location,
pub has_semicolon: bool,
_marker: PhantomData<&'ast ()>,
}
#[derive(Clone, Copy)]
pub struct Statement<'ast> {
ptr: NonNull<StatementHeader<'ast>>,
_marker: PhantomData<&'ast StatementHeader<'ast>>,
}
impl<'ast> std::ops::Deref for Statement<'ast> {
type Target = StatementHeader<'ast>;
fn deref(&self) -> &Self::Target {
self.header()
}
}
impl fmt::Debug for Statement<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.tag {
StatementTag::Block => fmt::Debug::fmt(&self.as_block_unchecked(), formatter),
StatementTag::Assign => fmt::Debug::fmt(self.as_assign_unchecked(), formatter),
StatementTag::CompoundAssign => {
fmt::Debug::fmt(self.as_compound_assign_unchecked(), formatter)
}
StatementTag::Break | StatementTag::Continue => formatter
.debug_struct("StatementUnit")
.field("tag", &self.tag)
.field("location", &self.location)
.field("has_semicolon", &self.has_semicolon)
.finish(),
StatementTag::Class => fmt::Debug::fmt(self.as_class_unchecked(), formatter),
StatementTag::Expression => fmt::Debug::fmt(self.as_expression_unchecked(), formatter),
StatementTag::NumericFor => fmt::Debug::fmt(self.as_numeric_for_unchecked(), formatter),
StatementTag::GenericFor => fmt::Debug::fmt(self.as_generic_for_unchecked(), formatter),
StatementTag::FunctionDeclaration => {
fmt::Debug::fmt(self.as_function_declaration_unchecked(), formatter)
}
StatementTag::If => fmt::Debug::fmt(self.as_if_unchecked(), formatter),
StatementTag::LocalFunction => {
fmt::Debug::fmt(self.as_local_function_unchecked(), formatter)
}
StatementTag::Local => fmt::Debug::fmt(self.as_local_unchecked(), formatter),
StatementTag::TypeAlias => fmt::Debug::fmt(self.as_type_alias_unchecked(), formatter),
StatementTag::TypeFunction => {
fmt::Debug::fmt(self.as_type_function_unchecked(), formatter)
}
StatementTag::DeclareGlobal => {
fmt::Debug::fmt(self.as_declare_global_unchecked(), formatter)
}
StatementTag::DeclareFunction => {
fmt::Debug::fmt(self.as_declare_function_unchecked(), formatter)
}
StatementTag::DeclareExternType => {
fmt::Debug::fmt(self.as_declare_extern_type_unchecked(), formatter)
}
StatementTag::Repeat => fmt::Debug::fmt(self.as_repeat_unchecked(), formatter),
StatementTag::Return => fmt::Debug::fmt(self.as_return_unchecked(), formatter),
StatementTag::While => fmt::Debug::fmt(self.as_while_unchecked(), formatter),
StatementTag::Error => fmt::Debug::fmt(self.as_error_unchecked(), formatter),
}
}
}
impl PartialEq for Statement<'_> {
fn eq(&self, other: &Self) -> bool {
match (self.tag, other.tag) {
(StatementTag::Block, StatementTag::Block) => self.as_block() == other.as_block(),
(StatementTag::Assign, StatementTag::Assign) => self.as_assign() == other.as_assign(),
(StatementTag::CompoundAssign, StatementTag::CompoundAssign) => {
self.as_compound_assign() == other.as_compound_assign()
}
(StatementTag::Break, StatementTag::Break)
| (StatementTag::Continue, StatementTag::Continue) => {
self.location == other.location && self.has_semicolon == other.has_semicolon
}
(StatementTag::Class, StatementTag::Class) => self.as_class() == other.as_class(),
(StatementTag::Expression, StatementTag::Expression) => {
self.as_expression() == other.as_expression()
}
(StatementTag::NumericFor, StatementTag::NumericFor) => {
self.as_numeric_for() == other.as_numeric_for()
}
(StatementTag::GenericFor, StatementTag::GenericFor) => {
self.as_generic_for() == other.as_generic_for()
}
(StatementTag::FunctionDeclaration, StatementTag::FunctionDeclaration) => {
self.as_function_declaration() == other.as_function_declaration()
}
(StatementTag::If, StatementTag::If) => self.as_if() == other.as_if(),
(StatementTag::LocalFunction, StatementTag::LocalFunction) => {
self.as_local_function() == other.as_local_function()
}
(StatementTag::Local, StatementTag::Local) => self.as_local() == other.as_local(),
(StatementTag::TypeAlias, StatementTag::TypeAlias) => {
self.as_type_alias() == other.as_type_alias()
}
(StatementTag::TypeFunction, StatementTag::TypeFunction) => {
self.as_type_function() == other.as_type_function()
}
(StatementTag::DeclareGlobal, StatementTag::DeclareGlobal) => {
self.as_declare_global() == other.as_declare_global()
}
(StatementTag::DeclareFunction, StatementTag::DeclareFunction) => {
self.as_declare_function() == other.as_declare_function()
}
(StatementTag::DeclareExternType, StatementTag::DeclareExternType) => {
self.as_declare_extern_type() == other.as_declare_extern_type()
}
(StatementTag::Repeat, StatementTag::Repeat) => self.as_repeat() == other.as_repeat(),
(StatementTag::Return, StatementTag::Return) => self.as_return() == other.as_return(),
(StatementTag::While, StatementTag::While) => self.as_while() == other.as_while(),
(StatementTag::Error, StatementTag::Error) => self.as_error() == other.as_error(),
_ => false,
}
}
}
#[repr(C)]
pub(crate) struct BlockNode<'ast> {
pub base: StatementHeader<'ast>,
pub statements: &'ast [Statement<'ast>],
pub has_end: bool,
}
#[derive(Clone, Copy)]
pub struct Block<'ast> {
ptr: NonNull<BlockNode<'ast>>,
_marker: PhantomData<&'ast BlockNode<'ast>>,
}
impl fmt::Debug for Block<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("Block")
.field("location", &self.location())
.field("has_semicolon", &self.has_semicolon())
.field("has_end", &self.has_end())
.field("statements", &self.as_slice())
.finish()
}
}
impl PartialEq for Block<'_> {
fn eq(&self, other: &Self) -> bool {
self.location() == other.location()
&& self.has_semicolon() == other.has_semicolon()
&& self.has_end() == other.has_end()
&& self.as_slice() == other.as_slice()
}
}
impl<'ast> Block<'ast> {
pub(crate) fn from_node(node: &'ast mut BlockNode<'ast>) -> Self {
Self {
ptr: NonNull::from(node),
_marker: PhantomData,
}
}
#[inline(always)]
fn node(&self) -> &BlockNode<'ast> {
unsafe { self.ptr.as_ref() }
}
pub fn as_statement(self) -> Statement<'ast> {
Statement {
ptr: self.ptr.cast(),
_marker: PhantomData,
}
}
pub fn location(self) -> Location {
self.node().base.location
}
pub fn has_semicolon(self) -> bool {
self.node().base.has_semicolon
}
pub fn has_end(self) -> bool {
self.node().has_end
}
pub fn as_slice(self) -> &'ast [Statement<'ast>] {
self.node().statements
}
pub fn len(self) -> usize {
self.as_slice().len()
}
pub fn is_empty(self) -> bool {
self.as_slice().is_empty()
}
pub fn first(self) -> Option<Statement<'ast>> {
self.as_slice().first().copied()
}
pub fn visit<V: AstVisitor>(self, visitor: &mut V) {
if !visitor.visit_block(self) {
return;
}
visit_statements(self.as_slice(), visitor);
}
}
impl<'ast> BlockNode<'ast> {
pub(crate) fn new(
statements: &'ast [Statement<'ast>],
has_end: bool,
location: Location,
) -> Self {
Self {
base: Statement::new_header(StatementTag::Block, location, false),
statements,
has_end,
}
}
}
impl<'ast> std::ops::Index<usize> for Block<'ast> {
type Output = Statement<'ast>;
fn index(&self, index: usize) -> &Self::Output {
&self.node().statements[index]
}
}
impl<'a, 'ast> IntoIterator for &'a Block<'ast> {
type Item = Statement<'ast>;
type IntoIter = std::iter::Copied<std::slice::Iter<'a, Statement<'ast>>>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter().copied()
}
}
macro_rules! stmt_node {
($name:ident { $($field:ident : $ty:ty),* $(,)? }, $tag:ident) => {
#[repr(C)]
pub struct $name<'ast> {
pub base: StatementHeader<'ast>,
$(pub $field: $ty),*
}
impl fmt::Debug for $name<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut debug = formatter.debug_struct(stringify!($name));
debug
.field("location", &self.location())
.field("has_semicolon", &self.has_semicolon());
$(debug.field(stringify!($field), &self.$field);)*
debug.finish()
}
}
impl PartialEq for $name<'_> {
fn eq(&self, other: &Self) -> bool {
self.location() == other.location()
&& self.has_semicolon() == other.has_semicolon()
$(&& self.$field == other.$field)*
}
}
impl<'ast> $name<'ast> {
#[allow(clippy::too_many_arguments)]
pub fn new(location: Location, has_semicolon: bool, $($field: $ty),*) -> Self {
Self {
base: Statement::new_header(StatementTag::$tag, location, has_semicolon),
$($field),*
}
}
pub fn location(&self) -> Location {
self.base.location
}
pub fn has_semicolon(&self) -> bool {
self.base.has_semicolon
}
}
};
}
#[repr(C)]
pub struct StatementUnit<'ast> {
pub base: StatementHeader<'ast>,
}
impl<'ast> StatementUnit<'ast> {
pub fn new(tag: StatementTag, location: Location, has_semicolon: bool) -> Self {
Self {
base: Statement::new_header(tag, location, has_semicolon),
}
}
}
impl fmt::Debug for StatementUnit<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("StatementUnit")
.field("tag", &self.base.tag)
.field("location", &self.base.location)
.field("has_semicolon", &self.base.has_semicolon)
.finish()
}
}
impl PartialEq for StatementUnit<'_> {
fn eq(&self, other: &Self) -> bool {
self.base.tag == other.base.tag
&& self.base.location == other.base.location
&& self.base.has_semicolon == other.base.has_semicolon
}
}
stmt_node!(StatementAssign {
vars: &'ast [Expression<'ast>],
values: &'ast [Expression<'ast>]
}, Assign);
stmt_node!(StatementCompoundAssign {
var: Expression<'ast>,
op: BinaryOp,
value: Expression<'ast>
}, CompoundAssign);
stmt_node!(StatementClass {
name: &'ast Local<'ast>,
super_class: Option<Expression<'ast>>,
members: &'ast [ClassMember<'ast>],
exported: bool
}, Class);
stmt_node!(StatementExpression {
expr: Expression<'ast>
}, Expression);
stmt_node!(StatementNumericFor {
name: &'ast Local<'ast>,
start: Expression<'ast>,
limit: Expression<'ast>,
step: Option<Expression<'ast>>,
body: Block<'ast>,
has_do: bool,
do_location: Location
}, NumericFor);
stmt_node!(StatementGenericFor {
names: &'ast [&'ast Local<'ast>],
values: &'ast [Expression<'ast>],
body: Block<'ast>,
has_in: bool,
in_location: Location,
has_do: bool,
do_location: Location
}, GenericFor);
stmt_node!(StatementFunctionDeclaration {
name: Expression<'ast>,
function: &'ast Function<'ast>
}, FunctionDeclaration);
stmt_node!(StatementIf {
condition: Expression<'ast>,
then_body: Block<'ast>,
else_body: Option<Statement<'ast>>,
then_location: Option<Location>,
else_location: Option<Location>
}, If);
stmt_node!(StatementLocalFunction {
name: &'ast Local<'ast>,
function: &'ast Function<'ast>,
is_const: bool,
const_keyword_begin: Position
}, LocalFunction);
stmt_node!(StatementLocal {
bindings: &'ast [&'ast Local<'ast>],
values: &'ast [Expression<'ast>],
keyword_location: Option<Location>,
equals_sign_location: Option<Location>,
is_const: bool,
is_exported: bool
}, Local);
stmt_node!(StatementTypeAlias {
name: AstName<'ast>,
name_location: Location,
generics: &'ast [&'ast GenericType<'ast>],
generic_packs: &'ast [&'ast GenericTypePack<'ast>],
exported: bool,
ty: Type<'ast>
}, TypeAlias);
stmt_node!(StatementTypeFunction {
name: AstName<'ast>,
name_location: Location,
exported: bool,
body: &'ast Function<'ast>,
has_errors: bool
}, TypeFunction);
stmt_node!(StatementDeclareGlobal {
name: AstName<'ast>,
name_location: Location,
ty: Type<'ast>
}, DeclareGlobal);
stmt_node!(StatementDeclareFunction {
name: AstName<'ast>,
name_location: Location,
params: TypeList<'ast>,
param_names: &'ast [ArgumentName<'ast>],
variadic: bool,
vararg_location: Location,
generics: &'ast [&'ast GenericType<'ast>],
generic_packs: &'ast [&'ast GenericTypePack<'ast>],
return_types: TypePack<'ast>,
attributes: &'ast [&'ast Attribute<'ast>]
}, DeclareFunction);
stmt_node!(StatementDeclareExternType {
name: AstName<'ast>,
super_name: Option<AstName<'ast>>,
props: &'ast [DeclaredExternTypeProperty<'ast>],
indexer: Option<&'ast TableTypeIndexer<'ast>>
}, DeclareExternType);
stmt_node!(StatementRepeat {
body: Block<'ast>,
condition: Expression<'ast>
}, Repeat);
stmt_node!(StatementReturn {
expressions: &'ast [Expression<'ast>]
}, Return);
stmt_node!(StatementWhile {
condition: Expression<'ast>,
body: Block<'ast>,
has_do: bool,
do_location: Location
}, While);
stmt_node!(StatementError {
expressions: &'ast [Expression<'ast>],
statements: &'ast [Statement<'ast>],
message_index: usize
}, Error);
impl<'ast> Statement<'ast> {
pub const fn new_header(
tag: StatementTag,
location: Location,
has_semicolon: bool,
) -> StatementHeader<'ast> {
StatementHeader {
tag,
location,
has_semicolon,
_marker: PhantomData,
}
}
pub(crate) fn from_node<T>(node: &'ast mut T) -> Self {
Self {
ptr: NonNull::from(node).cast(),
_marker: PhantomData,
}
}
pub fn as_ptr(self) -> *const () {
self.ptr.as_ptr().cast()
}
#[inline(always)]
fn header(&self) -> &StatementHeader<'ast> {
unsafe { self.ptr.as_ref() }
}
#[inline(always)]
fn header_mut(&mut self) -> &mut StatementHeader<'ast> {
unsafe { self.ptr.as_mut() }
}
#[inline(always)]
pub fn location(self) -> Location {
self.header().location
}
#[inline(always)]
pub fn has_semicolon(self) -> bool {
self.header().has_semicolon
}
pub fn is_checked_declare_function(&self) -> bool {
self.has_declare_function_attribute(AttributeKind::Checked)
}
pub fn has_declare_function_attribute(&self, kind: AttributeKind) -> bool {
self.get_declare_function_attribute(kind).is_some()
}
pub fn get_declare_function_attribute(&self, kind: AttributeKind) -> Option<&Attribute<'ast>> {
self.as_declare_function()
.and_then(|statement| find_attribute(statement.attributes, kind))
}
pub fn as_block(self) -> Option<Block<'ast>> {
(self.tag == StatementTag::Block).then(|| Block {
ptr: self.ptr.cast(),
_marker: PhantomData,
})
}
#[inline(always)]
pub(crate) fn as_block_unchecked(self) -> Block<'ast> {
debug_assert_eq!(self.tag, StatementTag::Block);
Block {
ptr: self.ptr.cast(),
_marker: PhantomData,
}
}
pub(crate) fn set_semicolon(mut self, location: Location) {
let header = self.header_mut();
header.has_semicolon = true;
header.location.end = location.end;
}
pub fn visit<V: AstVisitor>(self, visitor: &mut V) {
match self.tag {
StatementTag::Block => self.as_block_unchecked().visit(visitor),
StatementTag::Assign => {
let node = self.as_assign_unchecked();
if !visitor.visit_assign_statement(self) {
return;
}
visit_expressions(node.vars, visitor);
visit_expressions(node.values, visitor);
}
StatementTag::CompoundAssign => {
let node = self.as_compound_assign_unchecked();
if !visitor.visit_compound_assign_statement(self) {
return;
}
node.var.visit(visitor);
node.value.visit(visitor);
}
StatementTag::Break => {
let _ = visitor.visit_break_statement(self);
}
StatementTag::Continue => {
let _ = visitor.visit_continue_statement(self);
}
StatementTag::Class => {
let node = self.as_class_unchecked();
if !visitor.visit_class_statement(self) {
return;
}
if let Some(super_class) = node.super_class {
super_class.visit(visitor);
}
for member in node.members {
member.visit(visitor);
}
}
StatementTag::Expression => {
let node = self.as_expression_unchecked();
if !visitor.visit_expression_statement(self) {
return;
}
node.expr.visit(visitor);
}
StatementTag::NumericFor => {
let node = self.as_numeric_for_unchecked();
if !visitor.visit_numeric_for_statement(self) {
return;
}
node.name.visit(visitor);
node.start.visit(visitor);
node.limit.visit(visitor);
if let Some(step) = node.step {
step.visit(visitor);
}
node.body.visit(visitor);
}
StatementTag::GenericFor => {
let node = self.as_generic_for_unchecked();
if !visitor.visit_generic_for_statement(self) {
return;
}
for name in node.names {
name.visit(visitor);
}
visit_expressions(node.values, visitor);
node.body.visit(visitor);
}
StatementTag::FunctionDeclaration => {
let node = self.as_function_declaration_unchecked();
if !visitor.visit_function_declaration_statement(self) {
return;
}
node.name.visit(visitor);
node.function.visit(visitor);
}
StatementTag::If => {
let node = self.as_if_unchecked();
if !visitor.visit_if_statement(self) {
return;
}
node.condition.visit(visitor);
node.then_body.visit(visitor);
if let Some(else_body) = node.else_body {
else_body.visit(visitor);
}
}
StatementTag::LocalFunction => {
let node = self.as_local_function_unchecked();
if !visitor.visit_local_function_statement(self) {
return;
}
node.function.visit(visitor);
}
StatementTag::TypeFunction => {
let node = self.as_type_function_unchecked();
if !visitor.visit_type_function_statement(self) {
return;
}
node.body.visit(visitor);
}
StatementTag::Local => {
let node = self.as_local_unchecked();
if !visitor.visit_local_statement(self) {
return;
}
for binding in node.bindings {
binding.visit(visitor);
}
visit_expressions(node.values, visitor);
}
StatementTag::TypeAlias => {
let node = self.as_type_alias_unchecked();
if !visitor.visit_type_alias_statement(self) {
return;
}
for generic in node.generics {
generic.visit(visitor);
}
for generic_pack in node.generic_packs {
generic_pack.visit(visitor);
}
node.ty.visit(visitor);
}
StatementTag::DeclareGlobal => {
let node = self.as_declare_global_unchecked();
if !visitor.visit_declare_global_statement(self) {
return;
}
node.ty.visit(visitor);
}
StatementTag::DeclareFunction => {
let node = self.as_declare_function_unchecked();
if !visitor.visit_declare_function_statement(self) {
return;
}
node.params.visit(visitor);
node.return_types.visit(visitor);
}
StatementTag::DeclareExternType => {
let node = self.as_declare_extern_type_unchecked();
if !visitor.visit_declare_extern_type_statement(self) {
return;
}
for prop in node.props {
prop.ty.visit(visitor);
}
if let Some(indexer) = node.indexer {
indexer.index_type.visit(visitor);
indexer.result_type.visit(visitor);
}
}
StatementTag::Repeat => {
let node = self.as_repeat_unchecked();
if !visitor.visit_repeat_statement(self) {
return;
}
node.body.visit(visitor);
node.condition.visit(visitor);
}
StatementTag::Return => {
let node = self.as_return_unchecked();
if !visitor.visit_return_statement(self) {
return;
}
visit_expressions(node.expressions, visitor);
}
StatementTag::While => {
let node = self.as_while_unchecked();
if !visitor.visit_while_statement(self) {
return;
}
node.condition.visit(visitor);
node.body.visit(visitor);
}
StatementTag::Error => {
let node = self.as_error_unchecked();
if !visitor.visit_error_statement(self) {
return;
}
visit_expressions(node.expressions, visitor);
visit_statements(node.statements, visitor);
}
}
}
#[inline(always)]
fn cast_ref<T>(self) -> &'ast T {
unsafe { self.ptr.cast::<T>().as_ref() }
}
#[inline(always)]
fn cast_if_tag<T>(self, tag: StatementTag) -> Option<&'ast T> {
(self.tag == tag).then(|| self.cast_ref())
}
#[inline(always)]
fn cast_unchecked<T>(self, tag: StatementTag) -> &'ast T {
debug_assert_eq!(self.tag, tag);
self.cast_ref()
}
#[inline(always)]
pub fn as_assign(self) -> Option<&'ast StatementAssign<'ast>> {
self.cast_if_tag(StatementTag::Assign)
}
#[inline(always)]
pub(crate) fn as_assign_unchecked(self) -> &'ast StatementAssign<'ast> {
self.cast_unchecked(StatementTag::Assign)
}
#[inline(always)]
pub fn as_compound_assign(self) -> Option<&'ast StatementCompoundAssign<'ast>> {
self.cast_if_tag(StatementTag::CompoundAssign)
}
#[inline(always)]
pub(crate) fn as_compound_assign_unchecked(self) -> &'ast StatementCompoundAssign<'ast> {
self.cast_unchecked(StatementTag::CompoundAssign)
}
#[inline(always)]
pub fn as_class(self) -> Option<&'ast StatementClass<'ast>> {
self.cast_if_tag(StatementTag::Class)
}
#[inline(always)]
pub(crate) fn as_class_unchecked(self) -> &'ast StatementClass<'ast> {
self.cast_unchecked(StatementTag::Class)
}
#[inline(always)]
pub fn as_expression(self) -> Option<&'ast StatementExpression<'ast>> {
self.cast_if_tag(StatementTag::Expression)
}
#[inline(always)]
pub(crate) fn as_expression_unchecked(self) -> &'ast StatementExpression<'ast> {
self.cast_unchecked(StatementTag::Expression)
}
#[inline(always)]
pub fn as_numeric_for(self) -> Option<&'ast StatementNumericFor<'ast>> {
self.cast_if_tag(StatementTag::NumericFor)
}
#[inline(always)]
pub(crate) fn as_numeric_for_unchecked(self) -> &'ast StatementNumericFor<'ast> {
self.cast_unchecked(StatementTag::NumericFor)
}
#[inline(always)]
pub fn as_generic_for(self) -> Option<&'ast StatementGenericFor<'ast>> {
self.cast_if_tag(StatementTag::GenericFor)
}
#[inline(always)]
pub(crate) fn as_generic_for_unchecked(self) -> &'ast StatementGenericFor<'ast> {
self.cast_unchecked(StatementTag::GenericFor)
}
#[inline(always)]
pub fn as_function_declaration(self) -> Option<&'ast StatementFunctionDeclaration<'ast>> {
self.cast_if_tag(StatementTag::FunctionDeclaration)
}
#[inline(always)]
pub(crate) fn as_function_declaration_unchecked(
self,
) -> &'ast StatementFunctionDeclaration<'ast> {
self.cast_unchecked(StatementTag::FunctionDeclaration)
}
#[inline(always)]
pub fn as_if(self) -> Option<&'ast StatementIf<'ast>> {
self.cast_if_tag(StatementTag::If)
}
#[inline(always)]
pub(crate) fn as_if_unchecked(self) -> &'ast StatementIf<'ast> {
self.cast_unchecked(StatementTag::If)
}
#[inline(always)]
pub fn as_local_function(self) -> Option<&'ast StatementLocalFunction<'ast>> {
self.cast_if_tag(StatementTag::LocalFunction)
}
#[inline(always)]
pub(crate) fn as_local_function_unchecked(self) -> &'ast StatementLocalFunction<'ast> {
self.cast_unchecked(StatementTag::LocalFunction)
}
#[inline(always)]
pub fn as_local(self) -> Option<&'ast StatementLocal<'ast>> {
self.cast_if_tag(StatementTag::Local)
}
#[inline(always)]
pub(crate) fn as_local_unchecked(self) -> &'ast StatementLocal<'ast> {
self.cast_unchecked(StatementTag::Local)
}
#[inline(always)]
pub fn as_type_alias(self) -> Option<&'ast StatementTypeAlias<'ast>> {
self.cast_if_tag(StatementTag::TypeAlias)
}
#[inline(always)]
pub(crate) fn as_type_alias_unchecked(self) -> &'ast StatementTypeAlias<'ast> {
self.cast_unchecked(StatementTag::TypeAlias)
}
#[inline(always)]
pub fn as_type_function(self) -> Option<&'ast StatementTypeFunction<'ast>> {
self.cast_if_tag(StatementTag::TypeFunction)
}
#[inline(always)]
pub(crate) fn as_type_function_unchecked(self) -> &'ast StatementTypeFunction<'ast> {
self.cast_unchecked(StatementTag::TypeFunction)
}
#[inline(always)]
pub fn as_declare_global(self) -> Option<&'ast StatementDeclareGlobal<'ast>> {
self.cast_if_tag(StatementTag::DeclareGlobal)
}
#[inline(always)]
pub(crate) fn as_declare_global_unchecked(self) -> &'ast StatementDeclareGlobal<'ast> {
self.cast_unchecked(StatementTag::DeclareGlobal)
}
#[inline(always)]
pub fn as_declare_function(self) -> Option<&'ast StatementDeclareFunction<'ast>> {
self.cast_if_tag(StatementTag::DeclareFunction)
}
#[inline(always)]
pub(crate) fn as_declare_function_unchecked(self) -> &'ast StatementDeclareFunction<'ast> {
self.cast_unchecked(StatementTag::DeclareFunction)
}
#[inline(always)]
pub fn as_declare_extern_type(self) -> Option<&'ast StatementDeclareExternType<'ast>> {
self.cast_if_tag(StatementTag::DeclareExternType)
}
#[inline(always)]
pub(crate) fn as_declare_extern_type_unchecked(self) -> &'ast StatementDeclareExternType<'ast> {
self.cast_unchecked(StatementTag::DeclareExternType)
}
#[inline(always)]
pub fn as_repeat(self) -> Option<&'ast StatementRepeat<'ast>> {
self.cast_if_tag(StatementTag::Repeat)
}
#[inline(always)]
pub(crate) fn as_repeat_unchecked(self) -> &'ast StatementRepeat<'ast> {
self.cast_unchecked(StatementTag::Repeat)
}
#[inline(always)]
pub fn as_return(self) -> Option<&'ast StatementReturn<'ast>> {
self.cast_if_tag(StatementTag::Return)
}
#[inline(always)]
pub(crate) fn as_return_unchecked(self) -> &'ast StatementReturn<'ast> {
self.cast_unchecked(StatementTag::Return)
}
#[inline(always)]
pub fn as_while(self) -> Option<&'ast StatementWhile<'ast>> {
self.cast_if_tag(StatementTag::While)
}
#[inline(always)]
pub(crate) fn as_while_unchecked(self) -> &'ast StatementWhile<'ast> {
self.cast_unchecked(StatementTag::While)
}
#[inline(always)]
pub fn as_error(self) -> Option<&'ast StatementError<'ast>> {
self.cast_if_tag(StatementTag::Error)
}
#[inline(always)]
pub(crate) fn as_error_unchecked(self) -> &'ast StatementError<'ast> {
self.cast_unchecked(StatementTag::Error)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ClassMember<'ast> {
Property {
qualifier_location: Location,
name: AstName<'ast>,
name_location: Location,
type_colon_location: Option<Location>,
ty: Option<Type<'ast>>,
},
Method {
qualifier_location: Option<Location>,
keyword_location: Location,
function_name: AstName<'ast>,
name_location: Location,
function: &'ast Function<'ast>,
},
}
impl ClassMember<'_> {
pub fn name(&self) -> AstName<'_> {
match self {
Self::Property { name, .. } => *name,
Self::Method { function_name, .. } => *function_name,
}
}
pub fn visit<V: AstVisitor>(&self, visitor: &mut V) {
match self {
Self::Property { ty, .. } => {
if let Some(annotation) = ty {
annotation.visit(visitor);
}
}
Self::Method { function, .. } => function.visit(visitor),
}
}
}
impl AstArena {
pub(crate) fn alloc_block_node<'ast>(&'ast self, node: BlockNode<'ast>) -> Block<'ast> {
Block::from_node(self.alloc(node))
}
pub(crate) fn alloc_statement_node<'ast, T: 'ast>(&'ast self, node: T) -> Statement<'ast> {
Statement::from_node(self.alloc(node))
}
}