#![allow(clippy::large_enum_variant)]
use crate::span::{HasSpan, Span};
use crate::symbol::Symbol;
use crate::token::{Token, TokenKind, TokenValue};
use crate::visitor::{AstDescend, VisitorMut};
macro_rules! impl_span {
($name:ident, |$s:ident| $span:expr) => {
impl HasSpan for $name<'_> {
fn span(&self) -> Span {
let $s = self;
$span
}
}
};
($name:ident) => {
impl_span!($name, |s| s.0.span());
};
($name:ident, $field:ident) => {
impl_span!($name, |s| s.$field.span());
};
($name:ident, $start:ident, $end:ident) => {
impl_span!($name, |s| Span::consecutive(&s.$start, &s.$end));
};
}
macro_rules! impl_descend {
($name:ident: |$s:ident, $v:ident| $descend:expr) => {
impl<'a> AstDescend<'a> for $name<'a> {
fn descend_mut<T: VisitorMut<'a>>(&mut self, visitor: &mut T) {
let $s = self;
let $v = visitor;
$descend;
}
}
};
}
#[derive(Clone, Debug)]
pub struct TokenReference<'a> {
pub leading_trivia: Vec<Token<'a>>,
pub token: Token<'a>,
pub trailing_trivia: Vec<Token<'a>>,
}
impl_span!(TokenReference, token);
#[derive(Clone, Debug)]
pub struct NilLit<'a>(pub TokenReference<'a>);
impl_span!(NilLit);
#[derive(Clone, Debug)]
pub struct BooleanLit<'a>(pub TokenReference<'a>);
impl_span!(BooleanLit);
impl BooleanLit<'_> {
pub const TOKEN_KINDS: &'static [TokenKind] = &[
TokenKind::Symbol(Symbol::True),
TokenKind::Symbol(Symbol::False),
];
}
#[derive(Clone, Debug)]
pub struct NumberLit<'a>(pub TokenReference<'a>);
impl_span!(NumberLit);
#[derive(Clone, Debug)]
pub struct StringLit<'a>(pub TokenReference<'a>);
impl_span!(StringLit);
#[derive(Clone, Debug)]
pub struct Name<'a>(pub TokenReference<'a>);
impl_span!(Name);
#[derive(Clone, Debug)]
pub struct Vararg<'a>(pub TokenReference<'a>);
impl_span!(Vararg);
macro_rules! define_op {
($name:ident($kind:ident: $ty:ty); $($op:ident, $power:expr, $symbol:ident,)+) => {
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum $kind {
$($op,)+
}
impl $kind {
pub fn from_symbol(symbol: Symbol) -> Option<Self> {
match symbol {
$(Symbol::$symbol => Some(Self::$op),)+
_ => None
}
}
pub fn as_symbol(self) -> Symbol {
match self {
$(Self::$op => Symbol::$symbol,)+
}
}
pub fn binding_power(self) -> $ty {
match self {
$(Self::$op => $power,)+
}
}
}
#[derive(Clone, Debug)]
pub struct $name<'a>(
pub TokenReference<'a>
);
impl_span!($name);
impl $name<'_> {
pub const TOKEN_KINDS: &'static [TokenKind] =
&[$(TokenKind::Symbol(Symbol::$symbol),)+];
pub fn kind(&self) -> $kind {
match self.0.token.value {
TokenValue::Symbol(s) => $kind::from_symbol(s).expect("Invalid operator"),
_ => panic!("Invalid operator"),
}
}
}
}
}
define_op! {
BinOp(BinOpKind: (u8, u8));
Or, ( 1, 2), Or,
And, ( 3, 4), And,
Less, ( 5, 6), Less,
Greater, ( 5, 6), Greater,
LessEqual, ( 5, 6), LessEqual,
GreaterEqual, ( 5, 6), GreaterEqual,
NotEqual, ( 5, 6), NotEqual,
Equal, ( 5, 6), Equal,
BitOr, ( 7, 8), BitOr,
BitXor, ( 9, 10), BitXor,
BitAnd, (11, 12), BitAnd,
ShiftLeft, (13, 14), ShiftLeft,
ShiftRight, (13, 14), ShiftRight,
Concat, (16, 15), DoublePeriod,
Add, (17, 18), Add,
Sub, (17, 18), Sub,
Mul, (19, 20), Mul,
Div, (19, 20), Div,
IntDiv, (19, 20), IntDiv,
Rem, (19, 20), Rem,
Pow, (23, 22), Pow,
}
define_op! {
UnOp(UnOpKind: ((), u8));
Not, ( (), 21), Not,
Len, ( (), 21), Len,
Neg, ( (), 21), Sub,
BitNot, ( (), 21), BitXor,
}
#[derive(Clone, Debug)]
pub struct BinOpExpr<'a> {
pub left: Box<Expr<'a>>,
pub op: BinOp<'a>,
pub right: Box<Expr<'a>>,
}
impl_span!(BinOpExpr, left, right);
impl_descend!(BinOpExpr: |s, v| {
v.visit_expr(&mut s.left);
v.visit_expr(&mut s.right);
});
#[derive(Clone, Debug)]
pub struct UnOpExpr<'a> {
pub op: UnOp<'a>,
pub right: Box<Expr<'a>>,
}
impl_span!(UnOpExpr, op, right);
impl_descend!(UnOpExpr: |s, v| {
v.visit_expr(&mut s.right);
});
#[derive(Clone, Debug)]
pub struct Brackets<'a>(pub TokenReference<'a>, pub TokenReference<'a>);
impl_span!(Brackets, |s| Span::consecutive(&s.0, &s.1));
#[derive(Clone, Debug)]
pub struct ParenthesizedExpr<'a> {
pub brackets: Brackets<'a>,
pub expr: Box<Expr<'a>>,
}
impl_span!(ParenthesizedExpr, brackets);
#[derive(Clone, Debug)]
pub struct Punctuated<'a, T> {
pub pairs: Vec<(T, Option<TokenReference<'a>>)>,
}
impl<T: HasSpan> HasSpan for Punctuated<'_, T> {
fn span(&self) -> Span {
if self.pairs.is_empty() {
return Span::default();
}
let start = self.pairs[0].0.span();
let last = self.pairs.last().unwrap();
let end = last.1.as_ref().map(|v| v.span()).unwrap_or_else(|| last.0.span());
Span::consecutive(start, end)
}
}
#[derive(Clone, Debug)]
pub struct ParenthesizedList<'a, T> {
pub brackets: Brackets<'a>,
pub list: Punctuated<'a, T>,
}
impl<T> HasSpan for ParenthesizedList<'_, T> {
fn span(&self) -> Span {
self.brackets.span()
}
}
#[derive(Clone, Debug)]
pub enum VarField<'a> {
Expr {
brackets: Brackets<'a>,
key: Box<Expr<'a>>,
},
Name {
period: TokenReference<'a>,
key: Name<'a>,
},
}
impl_span!(VarField, |s| match s {
VarField::Expr { brackets, .. } => brackets.span(),
VarField::Name { period, key } => Span::consecutive(&period, &key),
});
impl_descend!(VarField: |s, v| match s {
VarField::Expr { ref mut key, .. } => v.visit_expr(key),
VarField::Name { ref mut key, .. } => v.visit_name(key),
});
#[derive(Clone, Debug)]
pub enum Var<'a> {
Name(Name<'a>),
Field(Box<PrefixExpr<'a>>, VarField<'a>),
}
impl_span!(Var, |s| match s {
Var::Name(inner) => inner.span(),
Var::Field(k, v) => Span::consecutive(&k, &v),
});
impl_descend!(Var: |s, v| match s {
Var::Name(ref mut name) => v.visit_name(name),
Var::Field(ref mut k, ref mut value) => {
v.visit_prefix_expr(k);
v.visit_var_field(value);
}
});
#[derive(Clone, Debug)]
pub enum FunctionCallee<'a> {
Expr(Box<PrefixExpr<'a>>),
Method {
object: Box<PrefixExpr<'a>>,
colon: TokenReference<'a>,
name: Name<'a>,
},
}
impl_span!(FunctionCallee, |s| match s {
FunctionCallee::Expr(inner) => inner.span(),
FunctionCallee::Method { object, name, .. } => Span::consecutive(&object, &name),
});
impl_descend!(FunctionCallee: |s, v| match s {
FunctionCallee::Expr(ref mut expr) => v.visit_prefix_expr(expr),
FunctionCallee::Method { ref mut object, ref mut name, .. } => {
v.visit_prefix_expr(object);
v.visit_name(name);
}
});
#[derive(Clone, Debug)]
pub enum FunctionArgs<'a> {
TableConstructor(TableConstructor<'a>),
StringLit(StringLit<'a>),
ParenthesizedList(ParenthesizedList<'a, Box<Expr<'a>>>),
}
impl_span!(FunctionArgs, |s| match s {
FunctionArgs::TableConstructor(inner) => inner.span(),
FunctionArgs::StringLit(inner) => inner.span(),
FunctionArgs::ParenthesizedList(inner) => inner.span(),
});
impl_descend!(FunctionArgs: |s, v| match s {
FunctionArgs::TableConstructor(ref mut tcons) => v.visit_table_constructor(tcons),
FunctionArgs::StringLit(ref mut string_lit) => v.visit_string_lit(string_lit),
FunctionArgs::ParenthesizedList(ref mut list) => for (item, _) in list.list.pairs.iter_mut() {
v.visit_expr(item);
}
});
#[derive(Clone, Debug)]
pub struct FunctionCall<'a> {
pub callee: FunctionCallee<'a>,
pub args: FunctionArgs<'a>,
}
impl_span!(FunctionCall, callee, args);
impl_descend!(FunctionCall: |s, v| {
v.visit_callee(&mut s.callee);
v.visit_args(&mut s.args);
});
#[derive(Clone, Debug)]
pub enum PrefixExpr<'a> {
Parenthesized(ParenthesizedExpr<'a>),
Var(Var<'a>),
Call(FunctionCall<'a>),
}
impl_span!(PrefixExpr, |s| match s {
PrefixExpr::Parenthesized(inner) => inner.span(),
PrefixExpr::Var(inner) => inner.span(),
PrefixExpr::Call(inner) => inner.span(),
});
impl_descend!(PrefixExpr: |s, v| match s {
PrefixExpr::Parenthesized(ParenthesizedExpr { ref mut expr, .. }) => v.visit_expr(expr),
PrefixExpr::Var(ref mut var) => v.visit_var(var),
PrefixExpr::Call(ref mut call) => v.visit_function_call(call),
});
#[derive(Clone, Debug)]
pub enum Expr<'a> {
Nil(NilLit<'a>),
Boolean(BooleanLit<'a>),
Number(NumberLit<'a>),
String(StringLit<'a>),
Vararg(Vararg<'a>),
UnOp(UnOpExpr<'a>),
BinOp(BinOpExpr<'a>),
TableConstructor(TableConstructor<'a>),
Prefix(PrefixExpr<'a>),
Function(FunctionExpr<'a>),
}
impl_span!(Expr, |s| match s {
Expr::Nil(inner) => inner.span(),
Expr::Boolean(inner) => inner.span(),
Expr::Number(inner) => inner.span(),
Expr::String(inner) => inner.span(),
Expr::Vararg(inner) => inner.span(),
Expr::UnOp(inner) => inner.span(),
Expr::BinOp(inner) => inner.span(),
Expr::TableConstructor(inner) => inner.span(),
Expr::Prefix(inner) => inner.span(),
Expr::Function(inner) => inner.span(),
});
impl_descend!(Expr: |s, v| match s {
Expr::Nil(ref mut nil_lit) => v.visit_nil_lit(nil_lit),
Expr::Boolean(ref mut boolean_lit) => v.visit_boolean_lit(boolean_lit),
Expr::Number(ref mut number_lit) => v.visit_number_lit(number_lit),
Expr::String(ref mut string_lit) => v.visit_string_lit(string_lit),
Expr::Vararg(ref mut vararg) => v.visit_vararg(vararg),
Expr::UnOp(ref mut un_op) => v.visit_un_op(un_op),
Expr::BinOp(ref mut bin_op) => v.visit_bin_op(bin_op),
Expr::TableConstructor(ref mut tcons) => v.visit_table_constructor(tcons),
Expr::Prefix(ref mut prefix_expr) => v.visit_prefix_expr(prefix_expr),
Expr::Function(ref mut function) => v.visit_function_expr(function),
});
#[derive(Clone, Debug)]
pub struct TableConstructor<'a> {
pub brackets: Brackets<'a>,
pub fields: Vec<TableField<'a>>,
}
impl_span!(TableConstructor, brackets);
impl_descend!(TableConstructor: |s, v| for item in s.fields.iter_mut() {
v.visit_table_field(item);
});
#[derive(Clone, Debug)]
pub enum TableKey<'a> {
Expr {
brackets: Brackets<'a>,
key: Box<Expr<'a>>,
},
Name {
key: Name<'a>,
},
}
impl_span!(TableKey, |s| match s {
TableKey::Expr { brackets, .. } => brackets.span(),
TableKey::Name { key } => key.span(),
});
impl_descend!(TableKey: |s, v| match s {
TableKey::Expr { ref mut key, .. } => v.visit_expr(key),
TableKey::Name { ref mut key } => v.visit_name(key),
});
#[derive(Clone, Debug)]
pub struct TableField<'a> {
pub key: Option<(TableKey<'a>, TokenReference<'a>)>,
pub value: Box<Expr<'a>>,
pub separator: Option<TokenReference<'a>>,
}
impl_span!(TableField, |s| {
let start = s.key.as_ref().map(|v| v.0.span()).unwrap_or_else(|| s.value.span());
let end = s
.separator
.as_ref()
.map(|v| v.span())
.unwrap_or_else(|| s.value.span());
Span::consecutive(start, end)
});
impl_descend!(TableField: |s, v| {
if let Some((ref mut key, _)) = s.key {
v.visit_table_key(key);
}
v.visit_expr(&mut s.value);
});
#[derive(Clone, Debug)]
pub struct Block<'a> {
pub statements: Vec<Statement<'a>>,
}
impl_span!(Block, |s| {
if s.statements.is_empty() {
return Span::default();
}
Span::consecutive(&s.statements[0], s.statements.last().unwrap())
});
impl_descend!(Block: |s, v| for stmt in s.statements.iter_mut() {
v.visit_stmt(stmt);
});
#[derive(Clone, Debug)]
pub enum Statement<'a> {
Empty(EmptyStat<'a>),
Block(BlockStat<'a>),
Return(ReturnStat<'a>),
Break(BreakStat<'a>),
Assignment(AssignmentStat<'a>),
FunctionCall(FunctionCall<'a>),
While(WhileStat<'a>),
For(ForStat<'a>),
Repeat(RepeatStat<'a>),
LocalDeclaration(LocalDeclarationStat<'a>),
FunctionDeclaration(FunctionDeclarationStat<'a>),
Label(LabelStat<'a>),
Goto(GotoStat<'a>),
If(IfStat<'a>),
}
impl_span!(Statement, |s| match s {
Statement::Empty(inner) => inner.span(),
Statement::Block(inner) => inner.span(),
Statement::Return(inner) => inner.span(),
Statement::Break(inner) => inner.span(),
Statement::Assignment(inner) => inner.span(),
Statement::FunctionCall(inner) => inner.span(),
Statement::While(inner) => inner.span(),
Statement::For(inner) => inner.span(),
Statement::Repeat(inner) => inner.span(),
Statement::LocalDeclaration(inner) => inner.span(),
Statement::FunctionDeclaration(inner) => inner.span(),
Statement::Label(inner) => inner.span(),
Statement::Goto(inner) => inner.span(),
Statement::If(inner) => inner.span(),
});
impl_descend!(Statement: |s, v| match s {
Statement::Empty(ref mut stmt) => v.visit_empty_stmt(stmt),
Statement::Block(BlockStat { ref mut block, .. }) => v.visit_block(block),
Statement::Return(ref mut stmt) => v.visit_return_stmt(stmt),
Statement::Break(ref mut stmt) => v.visit_break_stmt(stmt),
Statement::Assignment(ref mut stmt) => v.visit_assignment_stmt(stmt),
Statement::FunctionCall(ref mut stmt) => v.visit_function_call(stmt),
Statement::While(ref mut stmt) => v.visit_while_stmt(stmt),
Statement::For(ref mut stmt) => v.visit_for_stmt(stmt),
Statement::Repeat(ref mut stmt) => v.visit_repeat_stmt(stmt),
Statement::LocalDeclaration(ref mut stmt) => v.visit_local_decl(stmt),
Statement::FunctionDeclaration(ref mut stmt) => v.visit_function_decl(stmt),
Statement::Label(ref mut stmt) => v.visit_label_stmt(stmt),
Statement::Goto(ref mut stmt) => v.visit_goto_stmt(stmt),
Statement::If(ref mut stmt) => v.visit_if_stmt(stmt),
});
#[derive(Clone, Debug)]
pub struct EmptyStat<'a>(
pub TokenReference<'a>
);
impl_span!(EmptyStat);
#[derive(Clone, Debug)]
pub struct BlockStat<'a> {
pub do_: TokenReference<'a>,
pub block: Box<Block<'a>>,
pub end: TokenReference<'a>,
}
impl_span!(BlockStat, do_, end);
#[derive(Clone, Debug)]
pub struct ReturnStat<'a> {
pub return_: TokenReference<'a>,
pub exprs: Punctuated<'a, Box<Expr<'a>>>,
pub semi: Option<TokenReference<'a>>,
}
impl_span!(ReturnStat, |s| {
let end = s.semi.as_ref().map(|v| v.span()).unwrap_or_else(|| s.exprs.span());
Span::consecutive(&s.return_, end)
});
impl_descend!(ReturnStat: |s, v| for (item, _) in s.exprs.pairs.iter_mut() {
v.visit_expr(item);
});
#[derive(Clone, Debug)]
pub struct BreakStat<'a>(
pub TokenReference<'a>
);
impl_span!(BreakStat);
#[derive(Clone, Debug)]
pub struct AssignmentStat<'a> {
pub vars: Punctuated<'a, Var<'a>>,
pub assign: TokenReference<'a>,
pub exprs: Punctuated<'a, Box<Expr<'a>>>,
}
impl_span!(AssignmentStat, vars, exprs);
impl_descend!(AssignmentStat: |s, v| {
for (item, _) in &mut s.vars.pairs {
v.visit_var(item);
}
for (item, _) in &mut s.exprs.pairs {
v.visit_expr(item);
}
});
#[derive(Clone, Debug)]
pub struct WhileStat<'a> {
pub while_: TokenReference<'a>,
pub condition: Box<Expr<'a>>,
pub do_: TokenReference<'a>,
pub block: Box<Block<'a>>,
pub end: TokenReference<'a>,
}
impl_span!(WhileStat, while_, end);
impl_descend!(WhileStat: |s, v| {
v.visit_expr(&mut s.condition);
v.visit_block(&mut s.block);
});
#[derive(Clone, Debug)]
pub enum ForStat<'a> {
Generic(GenericFor<'a>),
Numerical(NumericalFor<'a>),
}
impl_span!(ForStat, |s| match s {
ForStat::Generic(inner) => inner.span(),
ForStat::Numerical(inner) => inner.span(),
});
impl_descend!(ForStat: |s, v| match s {
ForStat::Generic(ref mut inner) => v.visit_generic_for(inner),
ForStat::Numerical(ref mut inner) => v.visit_numerical_for(inner),
});
#[derive(Clone, Debug)]
pub struct GenericFor<'a> {
pub for_: TokenReference<'a>,
pub names: Punctuated<'a, Name<'a>>,
pub in_: TokenReference<'a>,
pub exprs: Punctuated<'a, Box<Expr<'a>>>,
pub do_: TokenReference<'a>,
pub block: Box<Block<'a>>,
pub end: TokenReference<'a>,
}
impl_span!(GenericFor, for_, end);
impl_descend!(GenericFor: |s, v| {
for (item, _) in &mut s.names.pairs {
v.visit_name(item);
}
for (item, _) in &mut s.exprs.pairs {
v.visit_expr(item);
}
v.visit_block(&mut s.block);
});
#[derive(Clone, Debug)]
pub struct NumericalFor<'a> {
pub for_: TokenReference<'a>,
pub name: Name<'a>,
pub assign: TokenReference<'a>,
pub from: Box<Expr<'a>>,
pub comma: TokenReference<'a>,
pub to: Box<Expr<'a>>,
pub step: Option<(TokenReference<'a>, Box<Expr<'a>>)>,
pub do_: TokenReference<'a>,
pub block: Box<Block<'a>>,
pub end: TokenReference<'a>,
}
impl_span!(NumericalFor, for_, end);
impl_descend!(NumericalFor: |s, v| {
v.visit_name(&mut s.name);
v.visit_expr(&mut s.from);
v.visit_expr(&mut s.to);
if let Some((_, ref mut expr)) = s.step {
v.visit_expr(expr);
}
v.visit_block(&mut s.block);
});
#[derive(Clone, Debug)]
pub struct RepeatStat<'a> {
pub repeat: TokenReference<'a>,
pub block: Box<Block<'a>>,
pub until: TokenReference<'a>,
pub condition: Expr<'a>,
}
impl_span!(RepeatStat, repeat, condition);
impl_descend!(RepeatStat: |s, v| {
v.visit_block(&mut s.block);
v.visit_expr(&mut s.condition);
});
#[derive(Clone, Debug)]
pub struct LocalDeclarationStat<'a> {
pub local: TokenReference<'a>,
pub names: Punctuated<'a, Name<'a>>,
pub definition: Option<LocalDefinition<'a>>,
}
impl_span!(LocalDeclarationStat, |s| {
let end = s
.definition
.as_ref()
.map(|v| v.span())
.unwrap_or_else(|| s.names.span());
Span::consecutive(&s.local, end)
});
impl_descend!(LocalDeclarationStat: |s, v| {
for (item, _) in &mut s.names.pairs {
v.visit_name(item);
}
if let Some(ref mut def) = s.definition {
for (item, _) in &mut def.exprs.pairs {
v.visit_expr(item);
}
}
});
#[derive(Clone, Debug)]
pub struct LocalDefinition<'a> {
pub assign: TokenReference<'a>,
pub exprs: Punctuated<'a, Box<Expr<'a>>>,
}
impl_span!(LocalDefinition, assign, exprs);
#[derive(Clone, Debug)]
pub enum FunctionDeclarationStat<'a> {
Local {
local: TokenReference<'a>,
function: TokenReference<'a>,
name: Name<'a>,
body: FunctionBody<'a>,
},
Nonlocal {
function: TokenReference<'a>,
name: FunctionName<'a>,
body: FunctionBody<'a>,
},
}
impl_span!(FunctionDeclarationStat, |s| match s {
FunctionDeclarationStat::Local { local, body, .. } => Span::consecutive(&local, &body),
FunctionDeclarationStat::Nonlocal { function, body, .. } => Span::consecutive(&function, &body),
});
impl_descend!(FunctionDeclarationStat: |s, v| match s {
FunctionDeclarationStat::Local { ref mut name, ref mut body, .. } => {
v.visit_name(name);
v.visit_function_body(body);
}
FunctionDeclarationStat::Nonlocal { ref mut name, ref mut body, .. } => {
name.descend_mut(v);
v.visit_function_body(body);
}
});
#[derive(Clone, Debug)]
pub struct FunctionBody<'a> {
pub params: ParenthesizedList<'a, Name<'a>>,
pub vararg: Option<Vararg<'a>>,
pub block: Box<Block<'a>>,
pub end: TokenReference<'a>,
}
impl_span!(FunctionBody, params, end);
impl_descend!(FunctionBody: |s, v| {
for (item, _) in &mut s.params.list.pairs {
v.visit_name(item);
}
if let Some(ref mut vararg) = s.vararg {
v.visit_vararg(vararg);
}
v.visit_block(&mut s.block);
});
#[derive(Clone, Debug)]
pub enum FunctionName<'a> {
PlainName(Name<'a>),
Indexed(Punctuated<'a, Name<'a>>),
Method {
receiver: Punctuated<'a, Name<'a>>,
colon: TokenReference<'a>,
method: Name<'a>,
},
}
impl_descend!(FunctionName: |s, v| match s {
FunctionName::PlainName(ref mut name) => v.visit_name(name),
FunctionName::Indexed(ref mut p) => for (item, _) in &mut p.pairs {
v.visit_name(item);
}
FunctionName::Method { ref mut receiver, ref mut method, .. } => {
for (item, _) in &mut receiver.pairs {
v.visit_name(item);
}
v.visit_name(method);
}
});
#[derive(Clone, Debug)]
pub struct FunctionExpr<'a> {
pub function: TokenReference<'a>,
pub body: FunctionBody<'a>,
}
impl_span!(FunctionExpr, function, body);
impl_descend!(FunctionExpr: |s, v| v.visit_function_body(&mut s.body));
#[derive(Clone, Debug)]
pub struct LabelStat<'a> {
pub preceding: TokenReference<'a>,
pub name: Name<'a>,
pub following: TokenReference<'a>,
}
impl_span!(LabelStat, preceding, following);
impl_descend!(LabelStat: |s, v| v.visit_name(&mut s.name));
#[derive(Clone, Debug)]
pub struct GotoStat<'a> {
pub goto: TokenReference<'a>,
pub label: Name<'a>,
}
impl_span!(GotoStat, goto, label);
impl_descend!(GotoStat: |s, v| v.visit_name(&mut s.label));
#[derive(Clone, Debug)]
pub struct IfStat<'a> {
pub if_: TokenReference<'a>,
pub condition: Expr<'a>,
pub then: TokenReference<'a>,
pub block: Box<Block<'a>>,
pub elseifs: Vec<ElseIf<'a>>,
pub else_: Option<Else<'a>>,
pub end: TokenReference<'a>,
}
impl_span!(IfStat, if_, end);
impl_descend!(IfStat: |s, v| {
v.visit_expr(&mut s.condition);
v.visit_block(&mut s.block);
for else_if in &mut s.elseifs {
else_if.descend_mut(v);
}
if let Some(ref mut else_) = s.else_ {
else_.descend_mut(v);
}
});
#[derive(Clone, Debug)]
pub struct ElseIf<'a> {
pub elseif: TokenReference<'a>,
pub condition: Expr<'a>,
pub then: TokenReference<'a>,
pub block: Block<'a>,
}
impl_span!(ElseIf, elseif, block);
impl_descend!(ElseIf: |s, v| {
v.visit_expr(&mut s.condition);
v.visit_block(&mut s.block);
});
#[derive(Clone, Debug)]
pub struct Else<'a> {
pub else_: TokenReference<'a>,
pub block: Block<'a>,
}
impl_span!(Else, else_, block);
impl_descend!(Else: |s, v| v.visit_block(&mut s.block));