use super::{
ast::{
BinOp, BinOpTy, Expr, ExprTy, Ident, Lit, PostOp, PostOpTy, PreOp,
PreOpTy,
},
SyntaxModifiers, SyntaxToken, SyntaxType, Walker,
};
use crate::{
diag::{ExprDiag, Semantic, Syntax},
lexer::{self, Token},
Either, Span,
};
use std::collections::VecDeque;
pub(super) fn expr_parser<'a, P: super::TokenStreamProvider<'a>>(
walker: &mut Walker<'a, P>,
mode: Mode,
end_tokens: impl AsRef<[Token]>,
) -> (Option<Expr>, Vec<Syntax>, Vec<Semantic>, Vec<SyntaxToken>) {
let start_position = match walker.peek() {
Some((_, span)) => span.start,
None => return (None, vec![], vec![], vec![]),
};
let mut parser = ShuntingYard {
stack: VecDeque::new(),
operators: VecDeque::new(),
groups: Vec::new(),
start_position,
mode,
syntax_diags: Vec::new(),
semantic_diags: Vec::new(),
syntax_tokens: Vec::new(),
};
parser.parse(walker, end_tokens.as_ref());
(
parser.create_ast(),
parser.syntax_diags,
parser.semantic_diags,
parser.syntax_tokens,
)
}
#[derive(Debug, PartialEq, Eq)]
pub(super) enum Mode {
Default,
DisallowTopLevelList,
BreakAtEq,
TakeOneUnit,
}
#[derive(Debug, Clone, PartialEq)]
struct Node {
ty: NodeTy,
span: Span,
}
#[derive(Debug, Clone, PartialEq)]
enum NodeTy {
Lit(Lit),
Ident(Ident),
Separator,
}
#[derive(Debug, Clone, PartialEq)]
struct Op {
ty: OpTy,
span: Span,
}
#[derive(Debug, Clone, PartialEq)]
enum OpTy {
Add(bool),
Sub(bool),
Mul(bool),
Div(bool),
Rem(bool),
And(bool),
Or(bool),
Xor(bool),
LShift(bool),
RShift(bool),
Eq(bool),
AddEq(bool),
SubEq(bool),
MulEq(bool),
DivEq(bool),
RemEq(bool),
AndEq(bool),
OrEq(bool),
XorEq(bool),
LShiftEq(bool),
RShiftEq(bool),
EqEq(bool),
NotEq(bool),
AndAnd(bool),
OrOr(bool),
XorXor(bool),
Gt(bool),
Lt(bool),
Ge(bool),
Le(bool),
ObjAccess(bool),
TernaryQ(bool),
TernaryC(bool),
AddPre(bool),
SubPre(bool),
Neg(bool),
Flip(bool),
Not(bool),
AddPost,
SubPost,
ParenStart,
FnCallStart,
IndexStart,
InitStart,
ArrInitStart,
Paren(bool, Span, Span),
FnCall(usize, Span, Span),
Index(bool, Span, Span),
Init(usize, Span, Span),
ArrInit(usize, Span, Span),
List(usize),
}
impl Op {
fn from_token(token: lexer::OpTy, span: Span) -> Self {
Self {
span,
ty: match token {
lexer::OpTy::Add => OpTy::Add(false),
lexer::OpTy::Sub => OpTy::Sub(false),
lexer::OpTy::Mul => OpTy::Mul(false),
lexer::OpTy::Div => OpTy::Div(false),
lexer::OpTy::Rem => OpTy::Rem(false),
lexer::OpTy::And => OpTy::And(false),
lexer::OpTy::Or => OpTy::Or(false),
lexer::OpTy::Xor => OpTy::Xor(false),
lexer::OpTy::LShift => OpTy::LShift(false),
lexer::OpTy::RShift => OpTy::RShift(false),
lexer::OpTy::Eq => OpTy::Eq(false),
lexer::OpTy::AddEq => OpTy::AddEq(false),
lexer::OpTy::SubEq => OpTy::SubEq(false),
lexer::OpTy::MulEq => OpTy::MulEq(false),
lexer::OpTy::DivEq => OpTy::DivEq(false),
lexer::OpTy::RemEq => OpTy::RemEq(false),
lexer::OpTy::AndEq => OpTy::AndEq(false),
lexer::OpTy::OrEq => OpTy::OrEq(false),
lexer::OpTy::XorEq => OpTy::XorEq(false),
lexer::OpTy::LShiftEq => OpTy::LShiftEq(false),
lexer::OpTy::RShiftEq => OpTy::RShiftEq(false),
lexer::OpTy::EqEq => OpTy::EqEq(false),
lexer::OpTy::NotEq => OpTy::NotEq(false),
lexer::OpTy::AndAnd => OpTy::AndAnd(false),
lexer::OpTy::OrOr => OpTy::OrOr(false),
lexer::OpTy::XorXor => OpTy::XorXor(false),
lexer::OpTy::Gt => OpTy::Gt(false),
lexer::OpTy::Lt => OpTy::Lt(false),
lexer::OpTy::Ge => OpTy::Ge(false),
lexer::OpTy::Le => OpTy::Le(false),
lexer::OpTy::Not
| lexer::OpTy::Flip
| lexer::OpTy::AddAdd
| lexer::OpTy::SubSub => {
unreachable!("[Op::from_token] Given a `token` which should never be handled by this function.")
}
},
}
}
#[rustfmt::skip]
fn precedence(&self) -> usize {
match &self.ty {
OpTy::ObjAccess(_) => 33,
OpTy::AddPost | OpTy::SubPost => 31,
OpTy::AddPre(_)
| OpTy::SubPre(_)
| OpTy::Neg(_)
| OpTy::Flip(_)
| OpTy::Not(_) => 29,
OpTy::Mul(_) | OpTy::Div(_) | OpTy::Rem(_) => 27,
OpTy::Add(_) | OpTy::Sub(_) => 25,
OpTy::LShift(_) | OpTy::RShift(_) => 23,
OpTy::Lt(_) | OpTy::Gt(_) | OpTy::Le(_) | OpTy::Ge(_) => 21,
OpTy::EqEq(_) | OpTy::NotEq(_) => 19,
OpTy::And(_) => 17,
OpTy::Xor(_) => 15,
OpTy::Or(_) => 13,
OpTy::AndAnd(_) => 11,
OpTy::XorXor(_) => 9,
OpTy::OrOr(_) => 7,
OpTy::TernaryQ(_) => 5,
OpTy::TernaryC(_) => 3,
OpTy::Eq(_)
| OpTy::AddEq(_)
| OpTy::SubEq(_)
| OpTy::MulEq(_)
| OpTy::DivEq(_)
| OpTy::RemEq(_)
| OpTy::AndEq(_)
| OpTy::XorEq(_)
| OpTy::OrEq(_)
| OpTy::LShiftEq(_)
| OpTy::RShiftEq(_) => 1,
_ => unreachable!("The operator {self:?} does not have a precedence value because it should never be passed into this function. Something has gone wrong!"),
}
}
fn to_bin_op(self) -> BinOp {
let ty = match self.ty {
OpTy::Add(_) => BinOpTy::Add,
OpTy::Sub(_) => BinOpTy::Sub,
OpTy::Mul(_) => BinOpTy::Mul,
OpTy::Div(_) => BinOpTy::Div,
OpTy::Rem(_) => BinOpTy::Rem,
OpTy::And(_) => BinOpTy::And,
OpTy::Or(_) => BinOpTy::Or,
OpTy::Xor(_) => BinOpTy::Xor,
OpTy::LShift(_) => BinOpTy::LShift,
OpTy::RShift(_) => BinOpTy::RShift,
OpTy::Eq(_) => BinOpTy::Eq,
OpTy::AddEq(_) => BinOpTy::AddEq,
OpTy::SubEq(_) => BinOpTy::SubEq,
OpTy::MulEq(_) => BinOpTy::MulEq,
OpTy::DivEq(_) => BinOpTy::DivEq,
OpTy::RemEq(_) => BinOpTy::RemEq,
OpTy::AndEq(_) => BinOpTy::AndEq,
OpTy::OrEq(_) => BinOpTy::OrEq,
OpTy::XorEq(_) => BinOpTy::XorEq,
OpTy::LShiftEq(_) => BinOpTy::LShiftEq,
OpTy::RShiftEq(_) => BinOpTy::RShiftEq,
OpTy::EqEq(_) => BinOpTy::EqEq,
OpTy::NotEq(_) => BinOpTy::NotEq,
OpTy::AndAnd(_) => BinOpTy::AndAnd,
OpTy::OrOr(_) => BinOpTy::OrOr,
OpTy::XorXor(_) => BinOpTy::XorXor,
OpTy::Gt(_) => BinOpTy::Gt,
OpTy::Lt(_) => BinOpTy::Lt,
OpTy::Ge(_) => BinOpTy::Ge,
OpTy::Le(_) => BinOpTy::Le,
_ => unreachable!("[Op::to_bin_op] Given a `ty` which should not be handled here.")
};
BinOp {
span: self.span,
ty,
}
}
}
#[derive(Debug, PartialEq)]
enum Group {
Paren(bool, Span),
FnCall(usize, Span),
Index(bool, Span),
Init(usize, Span),
ArrInit(usize, Span),
List(usize, usize),
Ternary,
}
struct ShuntingYard {
stack: VecDeque<Either<Node, Op>>,
operators: VecDeque<Op>,
groups: Vec<Group>,
start_position: usize,
mode: Mode,
syntax_diags: Vec<Syntax>,
semantic_diags: Vec<Semantic>,
syntax_tokens: Vec<SyntaxToken>,
}
impl ShuntingYard {
fn push_operator(&mut self, op: Op) {
if let OpTy::TernaryC(_) = op.ty {
match self.groups.pop() {
Some(group) => match group {
Group::Ternary => {}
_ => unreachable!("Should be in ternary group"),
},
None => unreachable!("Should be in ternary group"),
};
}
while self.operators.back().is_some() {
let back = self.operators.back().unwrap();
match back.ty {
OpTy::ParenStart
| OpTy::IndexStart
| OpTy::FnCallStart
| OpTy::InitStart
| OpTy::ArrInitStart => break,
_ => {}
}
match (&op.ty, &back.ty) {
(OpTy::ObjAccess(_), OpTy::ObjAccess(_)) => {
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
break;
}
(OpTy::TernaryC(_), OpTy::TernaryQ(_)) => {
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
break;
}
(OpTy::TernaryC(_), OpTy::TernaryC(_)) => {
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
continue;
}
(_, _) => {}
}
if op.precedence() < back.precedence() {
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
} else {
break;
}
}
self.operators.push_back(op);
}
fn collapse_paren(&mut self, group: Group, end_span: Span) {
if let Group::Paren(has_inner, l_paren) = group {
while self.operators.back().is_some() {
let op = self.operators.pop_back().unwrap();
#[cfg(debug_assertions)]
{
match op.ty {
OpTy::FnCallStart => unreachable!("Mismatch between operator stack (Op::FnCallStart) and group stack (Group::Paren)!"),
OpTy::IndexStart => unreachable!("Mismatch between operator stack (Op::IndexStart) and group stack (Group::Paren)!"),
OpTy::InitStart => unreachable!("Mismatch between operator stack (Op::InitStart) and group stack (Group::Paren)!"),
OpTy::ArrInitStart => unreachable!("Mismatch between operator stack (Op::ArrInitStart) and group stack (Group::Paren)!"),
_ => {}
}
}
if let OpTy::ParenStart = op.ty {
self.stack.push_back(Either::Right(Op {
span: Span::new(l_paren.start, end_span.end),
ty: OpTy::Paren(has_inner, l_paren, end_span),
}));
break;
} else {
self.stack.push_back(Either::Right(op));
}
}
} else {
unreachable!()
}
}
fn collapse_fn(&mut self, group: Group, end_span: Span) {
if let Group::FnCall(count, l_paren) = group {
while self.operators.back().is_some() {
let op = self.operators.pop_back().unwrap();
#[cfg(debug_assertions)]
{
match op.ty {
OpTy::ParenStart => unreachable!("Mismatch between operator stack (Op::ParenStart) and group stack (Group::Fn)!"),
OpTy::IndexStart => unreachable!("Mismatch between operator stack (Op::IndexStart) and group stack (Group::Fn)!"),
OpTy::InitStart => unreachable!("Mismatch between operator stack (Op::InitStart) and group stack (Group::Fn)!"),
OpTy::ArrInitStart => unreachable!("Mismatch between operator stack (Op::ArrInitStart) and group stack (Group::Fn)!"),
_ => {}
}
}
if let OpTy::FnCallStart = op.ty {
self.stack.push_back(Either::Right(Op {
span: Span::new(l_paren.start, end_span.end),
ty: OpTy::FnCall(count + 1, l_paren, end_span),
}));
break;
} else {
self.stack.push_back(Either::Right(op));
}
}
} else {
unreachable!()
}
}
fn collapse_index(&mut self, group: Group, end_span: Span) {
if let Group::Index(contains_i, l_bracket) = group {
while self.operators.back().is_some() {
let op = self.operators.pop_back().unwrap();
#[cfg(debug_assertions)]
{
match op .ty{
OpTy::ParenStart => unreachable!("Mismatch between operator stack (Op::ParenStart) and group stack (Group::Index)!"),
OpTy::FnCallStart => unreachable!("Mismatch between operator stack (Op::FnCallStart) and group stack (Group::Index)!"),
OpTy::InitStart=> unreachable!("Mismatch between operator stack (Op::InitStart) and group stack (Group::Index)!"),
OpTy::ArrInitStart => unreachable!("Mismatch between operator stack (Op::ArrInitStart) and group stack (Group::Index)!"),
_ => {}
}
}
if let OpTy::IndexStart = op.ty {
self.stack.push_back(Either::Right(Op {
span: Span::new(l_bracket.start, end_span.end),
ty: OpTy::Index(contains_i, l_bracket, end_span),
}));
break;
} else {
self.stack.push_back(Either::Right(op));
}
}
} else {
unreachable!()
}
}
fn collapse_init(&mut self, group: Group, end_span: Span) {
if let Group::Init(count, l_brace) = group {
while self.operators.back().is_some() {
let op = self.operators.pop_back().unwrap();
#[cfg(debug_assertions)]
{
match op.ty {
OpTy::ParenStart => unreachable!("Mismatch between operator stack (Op::ParenStart) and group stack (Group::Init)!"),
OpTy::IndexStart => unreachable!("Mismatch between operator stack (Op::IndexStart) and group stack (Group::Init)!"),
OpTy::FnCallStart => unreachable!("Mismatch between operator stack (Op::FnCallStart) and group stack (Group::Init)!"),
OpTy::ArrInitStart => unreachable!("Mismatch between operator stack (Op::ArrInitStart) and group stack (Group::Init)!"),
_ => {}
}
}
if let OpTy::InitStart = op.ty {
self.stack.push_back(Either::Right(Op {
span: Span::new(l_brace.start, end_span.end),
ty: OpTy::Init(count, l_brace, end_span),
}));
break;
} else {
self.stack.push_back(Either::Right(op));
}
}
} else {
unreachable!()
}
}
fn collapse_arr_init(&mut self, group: Group, end_span: Span) {
if let Group::ArrInit(count, l_paren) = group {
while self.operators.back().is_some() {
let op = self.operators.pop_back().unwrap();
#[cfg(debug_assertions)]
{
match op.ty {
OpTy::ParenStart => unreachable!("Mismatch between operator stack (Op::ParenStart) and group stack (Group::ArrInit)!"),
OpTy::IndexStart => unreachable!("Mismatch between operator stack (Op::IndexStart) and group stack (Group::ArrInit)!"),
OpTy::FnCallStart => unreachable!("Mismatch between operator stack (Op::FnCallStart) and group stack (Group::ArrInit)!"),
OpTy::InitStart => unreachable!("Mismatch between operator stack (Op::InitStart) and group stack (Group::ArrInit)!"),
_ => {}
}
}
if let OpTy::ArrInitStart = op.ty {
self.stack.push_back(Either::Right(Op {
span: Span::new(l_paren.start, end_span.end),
ty: OpTy::ArrInit(count + 1, l_paren, end_span),
}));
break;
} else {
self.stack.push_back(Either::Right(op));
}
}
} else {
unreachable!()
}
}
fn collapse_list(&mut self, group: Group, span_end: usize) {
if let Group::List(count, start_pos) = group {
while self.operators.back().is_some() {
let op = self.operators.back().unwrap();
#[cfg(debug_assertions)]
{
match op.ty {
OpTy::FnCallStart => unreachable!("Mismatch between operator stack (Op::FnCallStart) and group stack (Group::List)!"),
OpTy::InitStart => unreachable!("Mismatch between operator stack (Op::InitStart) and group stack (Group::List)!"),
OpTy::ArrInitStart => unreachable!("Mismatch between operator stack (Op::ArrInitStart) and group stack (Group::List)!"),
_ => {}
}
}
match op.ty {
OpTy::ParenStart | OpTy::IndexStart => break,
_ => {
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
}
}
}
self.stack.push_back(Either::Right(Op {
span: Span::new(start_pos, span_end),
ty: OpTy::List(count),
}));
} else {
unreachable!()
}
}
fn end_paren_fn(&mut self, end_span: Span) -> Result<(), ()> {
let current_group = match self.groups.last() {
Some(t) => t,
None => {
return Err(());
}
};
match current_group {
Group::Paren(_, _) => {}
Group::FnCall(_, _) | Group::ArrInit(_, _) => {}
_ => {
if self.exists_paren_fn_group() {
'inner: while let Some(current_group) = self.groups.last() {
match current_group {
Group::Init(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_init(
current_group,
Span::new(
end_span.end_at_previous().end,
end_span.end_at_previous().end,
),
);
}
Group::Index(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_index(
current_group,
end_span.start_zero_width(),
)
}
Group::List(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_list(
current_group,
end_span.end_at_previous().end,
);
}
Group::Ternary => {
'tern: while let Some(op) =
self.operators.back()
{
if let OpTy::TernaryQ(_) = op.ty {
let moved =
self.operators.pop_back().unwrap();
self.stack
.push_back(Either::Right(moved));
break 'tern;
} else {
let moved =
self.operators.pop_back().unwrap();
self.stack
.push_back(Either::Right(moved));
}
}
self.groups.pop();
}
Group::Paren(_, _)
| Group::FnCall(_, _)
| Group::ArrInit(_, _) => break 'inner,
}
}
} else {
return Err(());
}
}
}
let group = self.groups.pop().unwrap();
match group {
Group::Paren(_, _) => self.collapse_paren(group, end_span),
Group::FnCall(_, _) => self.collapse_fn(group, end_span),
Group::ArrInit(_, _) => self.collapse_arr_init(group, end_span),
_ => unreachable!(),
}
Ok(())
}
fn end_index(&mut self, end_span: Span) -> Result<(), ()> {
let current_group = match self.groups.last() {
Some(t) => t,
None => {
return Err(());
}
};
if std::mem::discriminant(current_group)
!= std::mem::discriminant(&Group::Index(
false,
Span::new_zero_width(0),
)) {
if self.exists_index_group() {
'inner: while let Some(current_group) = self.groups.last() {
match current_group {
Group::Paren(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_paren(
current_group,
Span::new(
end_span.end_at_previous().end,
end_span.end_at_previous().end,
),
);
}
Group::FnCall(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_fn(
current_group,
Span::new(
end_span.end_at_previous().end,
end_span.end_at_previous().end,
),
);
}
Group::Init(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_init(
current_group,
Span::new(
end_span.end_at_previous().end,
end_span.end_at_previous().end,
),
);
}
Group::ArrInit(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_arr_init(
current_group,
Span::new(
end_span.end_at_previous().end,
end_span.end_at_previous().end,
),
);
}
Group::Ternary => {
'tern: while let Some(op) = self.operators.back() {
if let OpTy::TernaryQ(_) = op.ty {
let moved =
self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
break 'tern;
} else {
let moved =
self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
}
}
self.groups.pop();
}
Group::List(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_list(
current_group,
end_span.end_at_previous().end,
)
}
Group::Index(_, _) => break 'inner,
}
}
} else {
return Err(());
}
}
let group = self.groups.pop().unwrap();
self.collapse_index(group, end_span);
Ok(())
}
fn end_init(&mut self, end_span: Span) -> Result<(), ()> {
let current_group = match self.groups.last() {
Some(t) => t,
None => {
return Err(());
}
};
if std::mem::discriminant(current_group)
!= std::mem::discriminant(&Group::Init(0, Span::new_zero_width(0)))
{
if self.exists_init_group() {
'inner: while let Some(current_group) = self.groups.last() {
match current_group {
Group::Paren(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_paren(
current_group,
Span::new(
end_span.end_at_previous().end,
end_span.end_at_previous().end,
),
);
}
Group::Index(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_index(
current_group,
end_span.start_zero_width(),
);
}
Group::FnCall(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_fn(
current_group,
Span::new(
end_span.end_at_previous().end,
end_span.end_at_previous().end,
),
);
}
Group::ArrInit(_, _) => {
let current_group = self.groups.pop().unwrap();
self.collapse_arr_init(
current_group,
Span::new(
end_span.end_at_previous().end,
end_span.end_at_previous().end,
),
);
}
Group::Ternary => {
'tern: while let Some(op) = self.operators.back() {
if let OpTy::TernaryQ(_) = op.ty {
let moved =
self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
break 'tern;
} else {
let moved =
self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
}
}
self.groups.pop();
}
Group::List(_, _) => unreachable!(),
Group::Init(_, _) => break 'inner,
}
}
} else {
return Err(());
}
}
let group = self.groups.pop().unwrap();
self.collapse_init(group, end_span);
Ok(())
}
fn register_arity_argument(&mut self, end_span: Span) {
while let Some(group) = self.groups.last_mut() {
match group {
Group::FnCall(count, _)
| Group::Init(count, _)
| Group::ArrInit(count, _) => {
while self.operators.back().is_some() {
let back = self.operators.back().unwrap();
match back.ty {
OpTy::FnCallStart
| OpTy::InitStart
| OpTy::ArrInitStart => break,
_ => {}
}
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
}
*count += 1;
return;
}
Group::List(count, _) => {
while self.operators.back().is_some() {
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
}
*count += 1;
return;
}
Group::Paren(_, _) => {
let group = self.groups.pop().unwrap();
self.collapse_paren(group, end_span);
}
Group::Index(_, _) => {
let group = self.groups.pop().unwrap();
self.collapse_index(group, end_span);
}
Group::Ternary => {
'tern: while let Some(op) = self.operators.back() {
if let OpTy::TernaryQ(_) = op.ty {
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
break 'tern;
} else {
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
}
}
self.groups.pop();
}
}
}
while self.operators.back().is_some() {
let moved = self.operators.pop_back().unwrap();
self.stack.push_back(Either::Right(moved));
}
self.groups.push(Group::List(
if self.stack.is_empty() && self.operators.is_empty() {
0
} else {
1
},
self.start_position,
))
}
fn set_op_rhs_toggle(&mut self) {
if let Some(op) = self.operators.back_mut() {
match &mut op.ty {
OpTy::Add(b)
| OpTy::Sub(b)
| OpTy::Mul(b)
| OpTy::Div(b)
| OpTy::Rem(b)
| OpTy::And(b)
| OpTy::Or(b)
| OpTy::Xor(b)
| OpTy::LShift(b)
| OpTy::RShift(b)
| OpTy::Eq(b)
| OpTy::AddEq(b)
| OpTy::SubEq(b)
| OpTy::MulEq(b)
| OpTy::DivEq(b)
| OpTy::RemEq(b)
| OpTy::AndEq(b)
| OpTy::OrEq(b)
| OpTy::XorEq(b)
| OpTy::LShiftEq(b)
| OpTy::RShiftEq(b)
| OpTy::EqEq(b)
| OpTy::NotEq(b)
| OpTy::AndAnd(b)
| OpTy::OrOr(b)
| OpTy::XorXor(b)
| OpTy::Gt(b)
| OpTy::Lt(b)
| OpTy::Ge(b)
| OpTy::Le(b)
| OpTy::AddPre(b)
| OpTy::SubPre(b)
| OpTy::Neg(b)
| OpTy::Flip(b)
| OpTy::Not(b)
| OpTy::TernaryQ(b)
| OpTy::TernaryC(b)
| OpTy::ObjAccess(b) => *b = true,
_ => {}
}
}
if let Some(group) = self.groups.last_mut() {
match group {
Group::Paren(b, _) | Group::Index(b, _) => *b = true,
_ => {}
}
}
}
fn just_started_paren(&self) -> bool {
if let Some(current_group) = self.groups.last() {
match current_group {
Group::Paren(has_inner, _) => *has_inner == false,
_ => false,
}
} else {
false
}
}
fn just_started_fn_arr_init(&self) -> bool {
let stack_span = self.stack.back().map(|i| match i {
Either::Left(e) => e.span,
Either::Right(op) => op.span,
});
let op_span = match self.operators.back() {
Some(op) => match op.ty {
OpTy::FnCallStart | OpTy::ArrInitStart => op.span,
_ => return false,
},
None => return false,
};
match (stack_span, op_span) {
(Some(stack), op_span) => op_span.is_after(&stack),
(None, _op_span) => true,
}
}
fn just_started_init(&self) -> bool {
if let Some(current_group) = self.groups.last() {
match current_group {
Group::Init(count, _) => *count == 0,
_ => false,
}
} else {
false
}
}
fn is_in_ternary(&self) -> bool {
if let Some(current_group) = self.groups.last() {
match current_group {
Group::Ternary => true,
_ => false,
}
} else {
false
}
}
fn is_in_variable_arg_group(&self) -> bool {
if let Some(current_group) = self.groups.last() {
match current_group {
Group::FnCall(_, _)
| Group::Init(_, _)
| Group::ArrInit(_, _)
| Group::List(_, _) => true,
Group::Ternary => {
for group in self.groups.iter().rev() {
match group {
Group::FnCall(_, _)
| Group::Init(_, _)
| Group::ArrInit(_, _)
| Group::List(_, _) => return true,
_ => {}
}
}
false
}
_ => false,
}
} else {
false
}
}
fn exists_paren_fn_group(&self) -> bool {
for group in self.groups.iter() {
match group {
Group::Paren(_, _)
| Group::FnCall(_, _)
| Group::ArrInit(_, _) => return true,
_ => {}
}
}
false
}
fn exists_index_group(&self) -> bool {
for group in self.groups.iter() {
if let Group::Index(_, _) = group {
return true;
}
}
false
}
fn exists_init_group(&self) -> bool {
for group in self.groups.iter() {
if let Group::Init(_, _) = group {
return true;
}
}
false
}
fn get_previous_span(&self) -> Option<Span> {
let stack_span = self.stack.back().map(|i| match i {
Either::Left(e) => e.span,
Either::Right(op) => op.span,
});
let op_span = self.operators.back().map(|op| op.span);
match (stack_span, op_span) {
(Some(stack), Some(op)) => {
if stack.is_after(&op) {
stack_span
} else {
op_span
}
}
(Some(_), None) => stack_span,
(None, Some(_)) => op_span,
(None, None) => None,
}
}
fn colour<'a, P: super::TokenStreamProvider<'a>>(
&mut self,
walker: &Walker<'a, P>,
span: Span,
token: SyntaxType,
) {
if walker.streams.len() == 1 {
self.syntax_tokens.push(SyntaxToken {
ty: token,
modifiers: SyntaxModifiers::empty(),
span,
});
}
}
fn parse<'a, P: super::TokenStreamProvider<'a>>(
&mut self,
walker: &mut Walker<'a, P>,
end_tokens: &[Token],
) {
#[derive(PartialEq)]
enum State {
Operand,
AfterOperand,
}
let mut state = State::Operand;
#[derive(PartialEq)]
enum Start {
None,
FnOrArr,
ArrInit,
EmptyIndex,
}
let mut can_start = Start::None;
#[derive(PartialEq)]
enum Arity {
None,
PotentialEnd,
Operator,
}
let mut arity_state = Arity::None;
let mut just_started_arity_group = true;
'main: while !walker.is_done() {
let (token, span) = match walker.peek() {
Some(t) => t,
None => break 'main,
};
if end_tokens.contains(token) {
if *token == Token::RParen && self.exists_paren_fn_group() {
} else if *token == Token::RBracket && self.exists_index_group()
{
} else if *token == Token::RBrace && self.exists_init_group() {
} else {
break 'main;
}
}
match token {
Token::Num { .. } | Token::Bool(_)
if state == State::Operand =>
{
if self.is_in_variable_arg_group()
&& arity_state == Arity::PotentialEnd
{
self.register_arity_argument(span.start_zero_width());
}
arity_state = Arity::PotentialEnd;
match Lit::parse(token, span) {
Ok(l) => self.stack.push_back(Either::Left(Node {
ty: NodeTy::Lit(l),
span,
})),
Err((l, d)) => {
self.stack.push_back(Either::Left(Node {
ty: NodeTy::Lit(l),
span,
}));
self.syntax_diags.push(d);
}
}
state = State::AfterOperand;
can_start = Start::None;
self.set_op_rhs_toggle();
self.colour(
walker,
span,
match token {
Token::Num { .. } => SyntaxType::Number,
Token::Bool(_) => SyntaxType::Boolean,
_ => unreachable!(),
},
);
}
Token::Num { .. } | Token::Bool(_)
if state == State::AfterOperand =>
{
if self.mode == Mode::TakeOneUnit {
break 'main;
}
if self.is_in_variable_arg_group()
&& arity_state == Arity::PotentialEnd
{
self.register_arity_argument(span.start_zero_width());
} else {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundOperandAfterOperand(
self.get_previous_span().unwrap(),
span,
),
));
break 'main;
}
arity_state = Arity::PotentialEnd;
match Lit::parse(token, span) {
Ok(l) => self.stack.push_back(Either::Left(Node {
ty: NodeTy::Lit(l),
span,
})),
Err((l, d)) => {
self.stack.push_back(Either::Left(Node {
ty: NodeTy::Lit(l),
span,
}));
self.syntax_diags.push(d);
}
}
can_start = Start::None;
self.colour(
walker,
span,
match token {
Token::Num { .. } => SyntaxType::Number,
Token::Bool(_) => SyntaxType::Boolean,
_ => unreachable!(),
},
);
}
Token::Ident(s) if state == State::Operand => {
if self.is_in_variable_arg_group()
&& arity_state == Arity::PotentialEnd
{
self.register_arity_argument(span.start_zero_width());
}
arity_state = Arity::PotentialEnd;
self.stack.push_back(Either::Left(Node {
ty: NodeTy::Ident(Ident {
name: s.clone(),
span,
}),
span,
}));
state = State::AfterOperand;
can_start = Start::FnOrArr;
self.set_op_rhs_toggle();
self.colour(walker, span, SyntaxType::UncheckedIdent);
}
Token::Ident(s) if state == State::AfterOperand => {
if self.mode == Mode::TakeOneUnit {
break 'main;
}
if self.is_in_variable_arg_group()
&& arity_state == Arity::PotentialEnd
{
self.register_arity_argument(span.start_zero_width());
} else {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundOperandAfterOperand(
self.get_previous_span().unwrap(),
span,
),
));
break 'main;
}
arity_state = Arity::PotentialEnd;
self.stack.push_back(Either::Left(Node {
ty: NodeTy::Ident(Ident {
name: s.clone(),
span,
}),
span,
}));
can_start = Start::FnOrArr;
self.colour(walker, span, SyntaxType::UncheckedIdent);
}
Token::Op(op) if state == State::Operand => {
if (self.mode == Mode::BreakAtEq
|| self.mode == Mode::TakeOneUnit)
&& *op == lexer::OpTy::Eq
{
break 'main;
}
match op {
lexer::OpTy::Sub
| lexer::OpTy::Not
| lexer::OpTy::Flip
| lexer::OpTy::AddAdd
| lexer::OpTy::SubSub => {
if self.is_in_variable_arg_group()
&& arity_state == Arity::PotentialEnd
{
self.register_arity_argument(
span.start_zero_width(),
);
arity_state = Arity::Operator;
}
self.set_op_rhs_toggle();
}
_ => {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::InvalidPrefixOperator(span),
));
break 'main;
}
}
match op {
lexer::OpTy::Sub => self.push_operator(Op {
span,
ty: OpTy::Neg(false),
}),
lexer::OpTy::Not => self.push_operator(Op {
span,
ty: OpTy::Not(false),
}),
lexer::OpTy::Flip => self.push_operator(Op {
span,
ty: OpTy::Flip(false),
}),
lexer::OpTy::AddAdd => self.push_operator(Op {
span,
ty: OpTy::AddPre(false),
}),
lexer::OpTy::SubSub => self.push_operator(Op {
span,
ty: OpTy::SubPre(false),
}),
_ => {
unreachable!()
}
}
can_start = Start::None;
self.colour(walker, span, SyntaxType::Operator);
}
Token::Op(op) if state == State::AfterOperand => {
if (self.mode == Mode::BreakAtEq
|| self.mode == Mode::TakeOneUnit)
&& *op == lexer::OpTy::Eq
{
break 'main;
}
match op {
lexer::OpTy::Flip | lexer::OpTy::Not => {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::InvalidBinOrPostOperator(span),
));
break 'main;
}
lexer::OpTy::AddAdd => {
self.push_operator(Op {
span,
ty: OpTy::AddPost,
});
}
lexer::OpTy::SubSub => {
self.push_operator(Op {
span,
ty: OpTy::SubPost,
});
}
_ => {
self.push_operator(Op::from_token(*op, span));
state = State::Operand;
}
}
arity_state = Arity::Operator;
can_start = Start::None;
self.colour(walker, span, SyntaxType::Operator);
}
Token::LParen if state == State::Operand => {
if self.is_in_variable_arg_group()
&& arity_state == Arity::PotentialEnd
{
self.register_arity_argument(span.start_zero_width());
}
arity_state = Arity::Operator;
self.set_op_rhs_toggle();
self.operators.push_back(Op {
span,
ty: OpTy::ParenStart,
});
self.groups.push(Group::Paren(false, span));
can_start = Start::None;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::LParen if state == State::AfterOperand => {
if can_start == Start::FnOrArr {
self.operators.push_back(Op {
span,
ty: OpTy::FnCallStart,
});
self.groups.push(Group::FnCall(0, span));
state = State::Operand;
can_start = Start::None;
just_started_arity_group = true;
} else if can_start == Start::ArrInit {
self.operators.push_back(Op {
span,
ty: OpTy::ArrInitStart,
});
self.groups.push(Group::ArrInit(0, span));
state = State::Operand;
can_start = Start::None;
just_started_arity_group = true;
} else {
if self.is_in_variable_arg_group()
&& arity_state == Arity::PotentialEnd
{
self.register_arity_argument(
span.start_zero_width(),
);
} else {
if self.mode != Mode::TakeOneUnit {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundOperandAfterOperand(
self.get_previous_span().unwrap(),
span,
),
));
}
break 'main;
}
self.set_op_rhs_toggle();
self.operators.push_back(Op {
span,
ty: OpTy::ParenStart,
});
self.groups.push(Group::Paren(false, span));
state = State::Operand;
can_start = Start::None;
}
arity_state = Arity::Operator;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::RParen if state == State::AfterOperand => {
if !self.just_started_fn_arr_init()
&& self.is_in_variable_arg_group()
{
self.register_arity_argument(span.start_zero_width());
}
arity_state = Arity::PotentialEnd;
match self.end_paren_fn(span) {
Ok(_) => {}
Err(_) => {
break 'main;
}
}
can_start = Start::None;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::RParen if state == State::Operand => {
if self.is_in_variable_arg_group()
&& !just_started_arity_group
{
self.register_arity_argument(span.start_zero_width());
}
arity_state = Arity::PotentialEnd;
let prev_op_span = self.get_previous_span();
let just_started_paren = self.just_started_paren();
let just_started_fn_arr_init =
self.just_started_fn_arr_init();
match self.end_paren_fn(span) {
Ok(_) => {}
Err(_) => {
break 'main;
}
}
if just_started_paren {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundEmptyParens(Span::new(
prev_op_span.unwrap().start,
span.end,
)),
));
} else if just_started_fn_arr_init {
} else {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundRParenInsteadOfOperand(
prev_op_span.unwrap(),
span,
),
))
}
state = State::AfterOperand;
can_start = Start::None;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::LBracket if state == State::AfterOperand => {
self.operators.push_back(Op {
span,
ty: OpTy::IndexStart,
});
self.groups.push(Group::Index(false, span));
state = State::Operand;
arity_state = Arity::Operator;
can_start = Start::EmptyIndex;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::LBracket if state == State::Operand => {
if self.mode != Mode::TakeOneUnit {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundLBracketInsteadOfOperand(
self.get_previous_span(),
span,
),
));
}
break 'main;
}
Token::RBracket if state == State::AfterOperand => {
match self.end_index(span) {
Ok(_) => {}
Err(_) => {
break 'main;
}
}
can_start = Start::ArrInit;
arity_state = Arity::PotentialEnd;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::RBracket if state == State::Operand => {
if can_start == Start::EmptyIndex {
match self.end_index(span) {
Ok(_) => {}
Err(_) => {
break 'main;
}
}
} else {
let prev_op_span = self.get_previous_span();
match self.end_index(span) {
Ok(_) => {}
Err(_) => {
break 'main;
}
}
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundRBracketInsteadOfOperand(
prev_op_span.unwrap(),
span,
),
));
}
state = State::AfterOperand;
arity_state = Arity::PotentialEnd;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::LBrace if state == State::Operand => {
if self.is_in_variable_arg_group()
&& arity_state == Arity::PotentialEnd
{
self.register_arity_argument(span.start_zero_width());
}
arity_state = Arity::Operator;
self.set_op_rhs_toggle();
self.operators.push_back(Op {
span,
ty: OpTy::InitStart,
});
self.groups.push(Group::Init(0, span));
can_start = Start::None;
just_started_arity_group = true;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::LBrace if state == State::AfterOperand => {
if self.is_in_variable_arg_group()
&& arity_state == Arity::PotentialEnd
{
self.register_arity_argument(span.start_zero_width());
} else {
if self.mode != Mode::TakeOneUnit {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundOperandAfterOperand(
self.get_previous_span().unwrap(),
span,
),
));
}
break 'main;
}
arity_state = Arity::Operator;
self.set_op_rhs_toggle();
self.operators.push_back(Op {
span,
ty: OpTy::InitStart,
});
self.groups.push(Group::Init(0, span));
state = State::Operand;
can_start = Start::None;
just_started_arity_group = true;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::RBrace if state == State::AfterOperand => {
if self.is_in_variable_arg_group() {
self.register_arity_argument(span.start_zero_width());
}
arity_state = Arity::PotentialEnd;
match self.end_init(span) {
Ok(_) => {}
Err(_) => {
break 'main;
}
}
can_start = Start::None;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::RBrace if state == State::Operand => {
if self.is_in_variable_arg_group()
&& !just_started_arity_group
{
self.register_arity_argument(span.start_zero_width());
}
let prev_arity = arity_state;
arity_state = Arity::PotentialEnd;
let prev_op_span = self.get_previous_span();
let empty_group = self.just_started_init();
match self.end_init(span) {
Ok(_) => {}
Err(_) => {
break 'main;
}
}
if !empty_group && prev_arity != Arity::PotentialEnd {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundRBraceInsteadOfOperand(
prev_op_span.unwrap(),
span,
),
));
}
state = State::AfterOperand;
can_start = Start::None;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::Comma if state == State::AfterOperand => {
if (self.mode == Mode::DisallowTopLevelList
|| self.mode == Mode::TakeOneUnit)
&& self.groups.is_empty()
{
break 'main;
}
if arity_state == Arity::PotentialEnd {
self.register_arity_argument(span.start_zero_width());
}
arity_state = Arity::PotentialEnd;
self.stack.push_back(Either::Left(Node {
span,
ty: NodeTy::Separator,
}));
state = State::Operand;
can_start = Start::None;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::Comma if state == State::Operand => {
if (self.mode == Mode::DisallowTopLevelList
|| self.mode == Mode::TakeOneUnit)
&& self.groups.is_empty()
{
break 'main;
}
if !self.operators.is_empty() {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundCommaInsteadOfOperand(
self.get_previous_span().unwrap(),
span,
),
));
} else if !self.stack.is_empty() {
if let Some(Either::Left(Node {
span: _,
ty: NodeTy::Separator,
})) = self.stack.back()
{
} else {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundCommaInsteadOfOperand(
self.get_previous_span().unwrap(),
span,
),
));
}
}
if can_start == Start::EmptyIndex {
match self.groups.last_mut() {
Some(g) => match g {
Group::Index(contains_i, _) => {
*contains_i = false;
}
_ => unreachable!(),
},
_ => unreachable!(),
}
}
if !just_started_arity_group
|| self.is_in_variable_arg_group() == false
{
self.register_arity_argument(span.start_zero_width());
}
arity_state = Arity::PotentialEnd;
self.stack.push_back(Either::Left(Node {
span,
ty: NodeTy::Separator,
}));
can_start = Start::None;
self.colour(walker, span, SyntaxType::Punctuation);
}
Token::Dot if state == State::AfterOperand => {
self.push_operator(Op {
span,
ty: OpTy::ObjAccess(false),
});
state = State::Operand;
can_start = Start::None;
arity_state = Arity::Operator;
self.colour(walker, span, SyntaxType::Operator);
}
Token::Dot if state == State::Operand => {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundDotInsteadOfOperand(
self.get_previous_span(),
span,
),
));
break 'main;
}
Token::Question => {
if state == State::Operand {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundQuestionInsteadOfOperand(
self.get_previous_span(),
span,
),
));
}
self.push_operator(Op {
span,
ty: OpTy::TernaryQ(false),
});
self.groups.push(Group::Ternary);
state = State::Operand;
can_start = Start::None;
arity_state = Arity::Operator;
self.colour(walker, span, SyntaxType::Operator);
}
Token::Colon => {
if !self.is_in_ternary() {
break 'main;
}
if state == State::Operand {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::FoundColonInsteadOfOperand(
self.get_previous_span(),
span,
),
));
}
self.push_operator(Op {
span,
ty: OpTy::TernaryC(false),
});
state = State::Operand;
can_start = Start::None;
arity_state = Arity::Operator;
self.colour(walker, span, SyntaxType::Operator);
}
_ => {
self.syntax_diags
.push(Syntax::Expr(ExprDiag::FoundInvalidToken(span)));
break 'main;
}
}
match token {
Token::LParen | Token::LBrace => {}
_ => just_started_arity_group = false,
}
walker.advance_expr_parser(
&mut self.syntax_diags,
&mut self.semantic_diags,
&mut self.syntax_tokens,
);
}
if !self.groups.is_empty() {
let group_end = self.get_previous_span().unwrap().end_zero_width();
while let Some(group) = self.groups.last_mut() {
match group {
Group::FnCall(_, _)
| Group::Init(_, _)
| Group::ArrInit(_, _) => {
if !just_started_arity_group {
self.register_arity_argument(group_end);
}
}
Group::List(count, _) => *count += 1,
_ => {}
}
just_started_arity_group = false;
let group = self.groups.pop().unwrap();
match group {
Group::Paren(_, l_paren) => {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::UnclosedParens(l_paren, group_end),
));
self.collapse_paren(group, group_end);
}
Group::Index(_, l_bracket) => {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::UnclosedIndexOperator(
l_bracket, group_end,
),
));
self.collapse_index(group, group_end)
}
Group::FnCall(_, l_paren) => {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::UnclosedFunctionCall(l_paren, group_end),
));
self.collapse_fn(group, group_end)
}
Group::Init(_, l_brace) => {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::UnclosedInitializerList(
l_brace, group_end,
),
));
self.collapse_init(group, group_end)
}
Group::ArrInit(_, l_paren) => {
self.syntax_diags.push(Syntax::Expr(
ExprDiag::UnclosedArrayConstructor(
l_paren, group_end,
),
));
self.collapse_arr_init(group, group_end)
}
Group::List(_, _) => {
self.collapse_list(group, group_end.end)
}
Group::Ternary => {}
}
}
}
while let Some(op) = self.operators.pop_back() {
self.stack.push_back(Either::Right(op));
}
}
fn create_ast(&mut self) -> Option<Expr> {
if self.stack.is_empty() {
return None;
}
let mut stack: VecDeque<Expr> = VecDeque::new();
let pop_back = |stack: &mut VecDeque<Expr>| stack.pop_back().unwrap();
while let Some(item) = self.stack.pop_front() {
match item {
Either::Left(node) => match node.ty {
NodeTy::Lit(lit) => stack.push_back(Expr {
span: node.span,
ty: ExprTy::Lit(lit),
}),
NodeTy::Ident(ident) => stack.push_back(Expr {
span: node.span,
ty: ExprTy::Ident(ident),
}),
NodeTy::Separator => stack.push_back(Expr {
span: node.span,
ty: ExprTy::Separator,
}),
},
Either::Right(op) => match op.ty {
OpTy::AddPre(has_operand) => {
let expr = if has_operand {
Some(pop_back(&mut stack))
} else {
None
};
let span = if let Some(ref expr) = expr {
Span::new(op.span.start, expr.span.end)
} else {
op.span
};
stack.push_back(Expr {
span,
ty: ExprTy::Prefix {
op: PreOp {
span: op.span,
ty: PreOpTy::Add,
},
expr: expr.map(|e| Box::from(e)),
},
});
}
OpTy::SubPre(has_operand) => {
let expr = if has_operand {
Some(pop_back(&mut stack))
} else {
None
};
let span = if let Some(ref expr) = expr {
Span::new(op.span.start, expr.span.end)
} else {
op.span
};
stack.push_back(Expr {
span,
ty: ExprTy::Prefix {
op: PreOp {
span: op.span,
ty: PreOpTy::Sub,
},
expr: expr.map(|e| Box::from(e)),
},
});
}
OpTy::AddPost => {
let expr = pop_back(&mut stack);
let span = Span::new(expr.span.start, op.span.end);
stack.push_back(Expr {
span,
ty: ExprTy::Postfix {
expr: Box::from(expr),
op: PostOp {
ty: PostOpTy::Add,
span: op.span,
},
},
});
}
OpTy::SubPost => {
let expr = pop_back(&mut stack);
let span = Span::new(expr.span.start, op.span.end);
stack.push_back(Expr {
span,
ty: ExprTy::Postfix {
expr: Box::from(expr),
op: PostOp {
ty: PostOpTy::Sub,
span: op.span,
},
},
});
}
OpTy::Neg(has_operand) => {
let expr = if has_operand {
Some(pop_back(&mut stack))
} else {
None
};
let span = if let Some(ref expr) = expr {
Span::new(op.span.start, expr.span.end)
} else {
op.span
};
stack.push_back(Expr {
span,
ty: ExprTy::Prefix {
op: PreOp {
span: op.span,
ty: PreOpTy::Neg,
},
expr: expr.map(|e| Box::from(e)),
},
});
}
OpTy::Flip(has_operand) => {
let expr = if has_operand {
Some(pop_back(&mut stack))
} else {
None
};
let span = if let Some(ref expr) = expr {
Span::new(op.span.start, expr.span.end)
} else {
op.span
};
stack.push_back(Expr {
span,
ty: ExprTy::Prefix {
op: PreOp {
span: op.span,
ty: PreOpTy::Flip,
},
expr: expr.map(|e| Box::from(e)),
},
});
}
OpTy::Not(has_operand) => {
let expr = if has_operand {
Some(pop_back(&mut stack))
} else {
None
};
let span = if let Some(ref expr) = expr {
Span::new(op.span.start, expr.span.end)
} else {
op.span
};
stack.push_back(Expr {
span,
ty: ExprTy::Prefix {
op: PreOp {
span: op.span,
ty: PreOpTy::Not,
},
expr: expr.map(|e| Box::from(e)),
},
});
}
OpTy::TernaryQ(has_rhs) => {
let last = pop_back(&mut stack);
let (cond, true_) = if has_rhs {
(pop_back(&mut stack), Some(last))
} else {
(last, None)
};
let span = if let Some(ref true_) = true_ {
Span::new(cond.span.start, true_.span.end)
} else {
Span::new(cond.span.start, op.span.end)
};
stack.push_back(Expr {
ty: ExprTy::Ternary {
cond: Box::from(cond),
true_: true_.map(|e| Box::from(e)),
false_: None,
},
span,
});
}
OpTy::TernaryC(has_rhs) => {
let last = pop_back(&mut stack);
let (prev, false_) = if has_rhs {
(pop_back(&mut stack), Some(last))
} else {
(last, None)
};
let (cond, true_) = match prev.ty {
ExprTy::Ternary {
cond,
true_,
false_: _,
} => (cond, true_),
_ => unreachable!(),
};
let span = if let Some(ref false_) = false_ {
Span::new(prev.span.start, false_.span.end)
} else {
Span::new(prev.span.start, op.span.end)
};
stack.push_back(Expr {
ty: ExprTy::Ternary {
cond,
true_,
false_: false_.map(|e| Box::from(e)),
},
span,
});
}
OpTy::Paren(has_inner, _l_paren, _end) => {
let expr = if has_inner {
Some(pop_back(&mut stack))
} else {
None
};
stack.push_back(Expr {
span: op.span,
ty: ExprTy::Parens {
expr: expr.map(|e| Box::from(e)),
},
});
}
OpTy::FnCall(count, l_paren, end) => {
let mut temp = VecDeque::new();
for _ in 0..count {
temp.push_front(pop_back(&mut stack));
}
let ident = match temp.pop_front().unwrap().ty {
ExprTy::Ident(ident) => ident,
_ => unreachable!("The first expression of a function call operator is not an identifier!")
};
let args = process_fn_arr_constructor_args(
temp,
&mut self.syntax_diags,
l_paren,
);
stack.push_back(Expr {
span: Span::new(ident.span.start, end.end),
ty: ExprTy::FnCall { ident, args },
});
}
OpTy::Index(contains_i, _l_bracket, end) => {
let i = if contains_i {
Some(Box::from(pop_back(&mut stack)))
} else {
None
};
let expr = pop_back(&mut stack);
stack.push_back(Expr {
span: Span::new(expr.span.start, end.end),
ty: ExprTy::Index {
item: Box::from(expr),
i,
},
});
}
OpTy::Init(count, l_brace, _end) => {
let mut temp = VecDeque::new();
for _ in 0..count {
temp.push_front(pop_back(&mut stack));
}
let args = process_initializer_list_args(
temp,
&mut self.syntax_diags,
l_brace,
);
stack.push_back(Expr {
ty: ExprTy::InitList { args },
span: op.span,
});
}
OpTy::ArrInit(count, l_paren, end) => {
let mut temp = VecDeque::new();
for _ in 0..count {
temp.push_front(pop_back(&mut stack));
}
let arr = temp.pop_front().unwrap();
match arr.ty {
ExprTy::Index { .. } => {}
_ => {
unreachable!("The first expression of an array constructor operator is not an `Expr::Index`!");
}
}
let args = process_fn_arr_constructor_args(
temp,
&mut self.syntax_diags,
l_paren,
);
stack.push_back(Expr {
span: Span::new(arr.span.start, end.end),
ty: ExprTy::ArrConstructor {
arr: Box::from(arr),
args,
},
});
}
OpTy::List(count) => {
let mut temp = VecDeque::new();
for _ in 0..count {
temp.push_front(pop_back(&mut stack));
}
let args =
process_list_args(temp, &mut self.syntax_diags);
stack.push_back(Expr {
ty: ExprTy::List { items: args },
span: op.span,
});
}
OpTy::ObjAccess(has_rhs) => {
let last = pop_back(&mut stack);
let (left, right) = if has_rhs {
(pop_back(&mut stack), Some(last))
} else {
(last, None)
};
let span = if let Some(ref right) = right {
Span::new(left.span.start, right.span.end)
} else {
Span::new(left.span.start, op.span.end)
};
stack.push_back(Expr {
ty: ExprTy::ObjAccess {
obj: Box::from(left),
leaf: right.map(|e| Box::from(e)),
},
span,
});
}
OpTy::Add(has_rhs)
| OpTy::Sub(has_rhs)
| OpTy::Mul(has_rhs)
| OpTy::Div(has_rhs)
| OpTy::Rem(has_rhs)
| OpTy::And(has_rhs)
| OpTy::Or(has_rhs)
| OpTy::Xor(has_rhs)
| OpTy::LShift(has_rhs)
| OpTy::RShift(has_rhs)
| OpTy::EqEq(has_rhs)
| OpTy::NotEq(has_rhs)
| OpTy::Gt(has_rhs)
| OpTy::Lt(has_rhs)
| OpTy::Ge(has_rhs)
| OpTy::Le(has_rhs)
| OpTy::AndAnd(has_rhs)
| OpTy::OrOr(has_rhs)
| OpTy::XorXor(has_rhs)
| OpTy::Eq(has_rhs)
| OpTy::AddEq(has_rhs)
| OpTy::SubEq(has_rhs)
| OpTy::MulEq(has_rhs)
| OpTy::DivEq(has_rhs)
| OpTy::RemEq(has_rhs)
| OpTy::AndEq(has_rhs)
| OpTy::OrEq(has_rhs)
| OpTy::XorEq(has_rhs)
| OpTy::LShiftEq(has_rhs)
| OpTy::RShiftEq(has_rhs) => {
let last = pop_back(&mut stack);
let (left, right) = if has_rhs {
(pop_back(&mut stack), Some(last))
} else {
(last, None)
};
let span = if let Some(ref right) = right {
Span::new(left.span.start, right.span.end)
} else {
Span::new(left.span.start, op.span.end)
};
let bin_op = op.to_bin_op();
stack.push_back(Expr {
ty: ExprTy::Binary {
left: Box::from(left),
op: bin_op,
right: right.map(|e| Box::from(e)),
},
span,
});
}
_ => {
unreachable!("Invalid operator {op:?} in shunting yard stack. This operator should never be present in the final RPN stack.");
}
},
}
}
if stack.len() > 1 {
let expr = pop_back(&mut stack);
stack.push_back(expr);
}
if stack.len() != 1 {
unreachable!("After processing the shunting yard output stack, we are left with more than one expression. This should not happen.");
}
Some(stack.pop_back().unwrap())
}
}
fn process_fn_arr_constructor_args(
mut list: VecDeque<Expr>,
diags: &mut Vec<Syntax>,
opening_delim: Span,
) -> Vec<Expr> {
let mut args = Vec::new();
enum Prev {
None,
Item(Span),
Comma(Span),
}
let mut previous = Prev::None;
while let Some(arg) = list.pop_front() {
match arg.ty {
ExprTy::Separator => {
match previous {
Prev::Comma(span) => {
diags.push(Syntax::Expr(
ExprDiag::ExpectedArgAfterComma(Span::new_between(
span, arg.span,
)),
));
}
Prev::None => {
diags.push(Syntax::Expr(
ExprDiag::ExpectedArgBetweenParenComma(
Span::new_between(opening_delim, arg.span),
),
));
}
_ => {}
}
previous = Prev::Comma(arg.span);
}
_ => {
match previous {
Prev::Item(span) => {
diags.push(Syntax::Expr(
ExprDiag::ExpectedCommaAfterArg(Span::new_between(
span, arg.span,
)),
));
}
_ => {}
}
previous = Prev::Item(arg.span);
args.push(arg);
}
}
}
if let Prev::Comma(span) = previous {
diags.push(Syntax::Expr(ExprDiag::ExpectedArgAfterComma(
span.next_single_width(),
)));
}
args
}
fn process_initializer_list_args(
mut list: VecDeque<Expr>,
diags: &mut Vec<Syntax>,
opening_delim: Span,
) -> Vec<Expr> {
let mut args = Vec::new();
enum Prev {
None,
Item(Span),
Comma(Span),
}
let mut previous = Prev::None;
while let Some(arg) = list.pop_front() {
match arg.ty {
ExprTy::Separator => {
match previous {
Prev::Comma(span) => {
diags.push(Syntax::Expr(
ExprDiag::ExpectedArgAfterComma(Span::new_between(
span, arg.span,
)),
));
}
Prev::None => {
diags.push(Syntax::Expr(
ExprDiag::ExpectedArgBetweenParenComma(
Span::new_between(opening_delim, arg.span),
),
));
}
_ => {}
}
previous = Prev::Comma(arg.span);
}
_ => {
match previous {
Prev::Item(span) => {
diags.push(Syntax::Expr(
ExprDiag::ExpectedCommaAfterArg(Span::new_between(
span, arg.span,
)),
));
}
_ => {}
}
previous = Prev::Item(arg.span);
args.push(arg);
}
}
}
args
}
fn process_list_args(
mut list: VecDeque<Expr>,
diags: &mut Vec<Syntax>,
) -> Vec<Expr> {
let mut args = Vec::new();
enum Prev {
None,
Item(Span),
Comma(Span),
}
let mut previous = Prev::None;
while let Some(arg) = list.pop_front() {
match arg.ty {
ExprTy::Separator => {
match previous {
Prev::Comma(span) => {
diags.push(Syntax::Expr(
ExprDiag::ExpectedExprAfterComma(
Span::new_between(span, arg.span),
),
));
}
Prev::None => {
diags.push(Syntax::Expr(
ExprDiag::ExpectedExprBeforeComma(
arg.span.previous_single_width(),
),
));
}
_ => {}
}
previous = Prev::Comma(arg.span);
}
_ => {
match previous {
Prev::Item(span) => {
diags.push(Syntax::Expr(
ExprDiag::ExpectedCommaAfterExpr(
Span::new_between(span, arg.span),
),
));
}
_ => {}
}
previous = Prev::Item(arg.span);
args.push(arg);
}
}
}
if let Prev::Comma(span) = previous {
diags.push(Syntax::Expr(ExprDiag::ExpectedExprAfterComma(
span.next_single_width(),
)));
}
args
}