use crate::lexer::token::Token;
use crate::util::BoolAsResult;
use crate::common::{ OperatorType, KeywordType, Primary, UNARY_OPERATORS, UNARY_POWER, BINARY_OPERATORS, get_bin_op_precedence };
use crate::tracking::{ SourceRegion };
use super::iterator::{ ParserIterator, UnwrapIndexWithIterator };
use super::ast::{ Expression, ExpressionData, CompoundField };
use super::pred;
use super::common;
use super::texpr::type_expression;
fn expr_primary (it: &mut ParserIterator) -> Option<Expression> {
let (primary, source) = it.expect_primary()?;
Some(Expression {
data: ExpressionData::Primary(primary),
source
})
}
fn expr_addr_of (it: &mut ParserIterator) -> Option<Expression> {
let SourceRegion { start, end: _ } = it.expect_specific_op(OperatorType::AddressOf)?;
let mutable = it.expect_specific_op(OperatorType::Mutable).is_some();
let expr = if let Some(expr) = pratt(UNARY_POWER, it) {
expr
} else {
it.simple_error(format!("Expected expression following unary operator ^{}", if mutable { "mut" } else { " "}));
return None;
};
let source = SourceRegion { start, end: expr.source.end };
Some(Expression {
data: ExpressionData::AddressOf { mutable, value: Box::new(expr) },
source
})
}
fn expr_sem_group (it: &mut ParserIterator) -> Option<Expression> {
let SourceRegion { start, end: _ } = it.expect_specific_op(OperatorType::LeftParen)?;
let expr = if let Some(expr) = expression(it) {
expr
} else {
it.simple_error("Expected expression following semantic group operator (".to_string());
it.synchronize_on_ops(pred::pair_counter(
pred::specific_op(OperatorType::LeftParen),
pred::specific_op(OperatorType::RightParen)
));
return None;
};
let end = if let Some(region) = it.expect_specific_op(OperatorType::RightParen) {
region.end
} else {
let (_, region) = it.synchronize_on_ops(pred::pair_counter(
pred::specific_op(OperatorType::LeftParen),
pred::specific_op(OperatorType::RightParen)
))?;
region.end
};
let source = SourceRegion { start, end };
Some(Expression {
data: expr.data,
source
})
}
fn expr_compound (it: &mut ParserIterator) -> Option<Expression> {
let (op, SourceRegion { start, end: _}) = it.expect_any_op_of(&[OperatorType::LeftBrace, OperatorType::Colon])?;
let mut value_ty = None;
if op == OperatorType::Colon {
if let Some(texpr) = type_expression(it) {
value_ty = Some(Box::new(texpr));
} else {
it.simple_error("Expected a compound literal type specifier to follow : (E.g. `:some_ty: [ 1, 2, 3]`)".to_string());
}
if !it.expect_specific_op(OperatorType::Colon).is_some() {
it.simple_error("Expected : to close compound literal type specifier".to_string());
it.synchronize(pred::or(
pred::specific_op(OperatorType::Colon),
pred::specific_op(OperatorType::LeftBrace)
)).as_result()?;
it.expect_specific_op(OperatorType::Colon);
}
if !it.expect_specific_op(OperatorType::LeftBrace).is_some() {
it.simple_error("Expected [ to begin compound literal field list".to_string());
it.synchronize_on_ops_with_limit(1, pred::specific_op(OperatorType::LeftBrace))?;
}
};
let mut fields = Vec::new();
let mut end = None;
let mut sep = true;
while it.valid() {
let err_msg: &'static str;
if let Some(SourceRegion { start: _, end: e }) = it.expect_specific_op(OperatorType::RightBrace) {
end = Some(e);
break
} else if sep {
if let Some(left) = expression(it) {
let mut right_err = false;
if let ExpressionData::Primary(Primary::Identifier(field_name)) = left.data {
if let Some(_) = it.expect_specific_op(OperatorType::Assign) {
if let Some(right) = expression(it) {
fields.push(CompoundField { name: Some(field_name), value: right });
sep = false;
continue
} else {
right_err = true;
}
}
}
if !right_err {
fields.push(CompoundField { name: None, value: left });
sep = false;
continue
} else {
err_msg = "field value expression to follow '[ident] =' in";
}
} else {
err_msg = "a name or value for field in";
}
} else if it.expect_specific_op(OperatorType::Comma).is_some() {
sep = true;
continue
} else {
err_msg = ", to separate fields or ] to end";
}
it.simple_error(format!("Expected {} compound literal", err_msg));
let (op, SourceRegion { start: _ , end: e }) = it.synchronize_on_ops(pred::contextual(
pred::specific_op(OperatorType::LeftBrace),
pred::specific_op(OperatorType::RightBrace),
pred::specific_op(OperatorType::Comma)
))?;
if op == OperatorType::Comma {
sep = true;
} else {
end = Some(e);
break
}
}
Some(Expression {
data: ExpressionData::Compound { value_ty, fields },
source: SourceRegion {
start,
end: end.unwrap_index_with_iterator(it, "Expected ] to end compound literal expression")
}
})
}
fn expr_unary (it: &mut ParserIterator) -> Option<Expression> {
let (op, SourceRegion { start, end: _ }) = it.expect_any_op_of(UNARY_OPERATORS)?;
let expr = if let Some(expr) = pratt(UNARY_POWER, it) {
expr
} else {
it.simple_error(format!("Expected expression following unary operator {}", op.as_text()));
return None;
};
let source = SourceRegion { start, end: expr.source.end };
Some(Expression {
data: ExpressionData::Unary { op, operand: Box::new(expr) },
source
})
}
fn expr_block (it: &mut ParserIterator) -> Option<Expression> {
let parser = if it.curr().is_specific_op(OperatorType::LeftBracket) {
common::block_expr_stmt
} else if it.curr().is_specific_kw(KeywordType::If) {
common::conditional_block
} else {
common::match_block
};
let block = (parser)(it)?;
let source = block.get_source();
if let Some(expr) = block.as_expression() {
Some(expr)
} else {
it.error(source, "This block is not valid in an expression context, there is no expression terminator".to_string());
None
}
}
fn expr_binary (left: Expression, it: &mut ParserIterator) -> Option<Expression> {
let (op, _) = it.expect_any_op_of(BINARY_OPERATORS)?;
let precedence = get_bin_op_precedence(op);
if let Some(right) = pratt(precedence, it) {
let source = SourceRegion { start: left.source.start, end: right.source.end };
Some(Expression {
data: ExpressionData::Binary { op, left: Box::new(left), right: Box::new(right) },
source
})
} else {
it.simple_error(format!("Expected right operand expression for binary operator {}", op.as_text()));
None
}
}
fn expr_else (left: Expression, it: &mut ParserIterator) -> Option<Expression> {
it.expect_specific_kw(KeywordType::Else)?;
if let Some(right) = expression(it) {
let source = SourceRegion { start: left.source.start, end: right.source.end };
Some(Expression {
data: ExpressionData::MatchExpression { left: Box::new(left), right: Box::new(right) },
source
})
} else {
it.simple_error("Expected right operand expression for match expression combination operator else".to_string());
None
}
}
fn expr_member (left: Expression, it: &mut ParserIterator) -> Option<Expression> {
it.expect_specific_op(OperatorType::Dot)?;
if let Some((member_name, SourceRegion { start: _, end })) = it.expect_ident() {
let source = SourceRegion { start: left.source.start, end };
Some(Expression {
data: ExpressionData::Member { operand: Box::new(left), member_name },
source
})
} else {
it.simple_error("Expected member name identifier for member access operator .".to_string());
None
}
}
fn expr_subscript (left: Expression, it: &mut ParserIterator) -> Option<Expression> {
it.expect_specific_op(OperatorType::LeftBrace)?;
if let Some(right) = expression(it) {
let end = if let Some(SourceRegion { start: _, end }) = it.expect_specific_op(OperatorType::RightBrace) {
end
} else {
it.simple_error("Expected ] to close subscript expression".to_string());
if let Some((_, SourceRegion { start: _, end })) = it.synchronize_on_ops(pred::pair_counter(
pred::specific_op(OperatorType::LeftBrace),
pred::specific_op(OperatorType::RightBrace)
)) {
end
} else {
return None;
}
};
let source = SourceRegion { start: left.source.start, end };
Some(Expression {
data: ExpressionData::Subscript { operand: Box::new(left), subscript: Box::new(right) },
source
})
} else {
it.simple_error("Expected expression to follow subscript operator [".to_string());
it.synchronize_on_ops(pred::pair_counter(
pred::specific_op(OperatorType::LeftBrace),
pred::specific_op(OperatorType::RightBrace)
));
None
}
}
fn expr_call (left: Expression, it: &mut ParserIterator) -> Option<Expression> {
it.expect_specific_op(OperatorType::LeftParen)?;
let mut parameters = Vec::new();
let mut end = None;
let mut sep = true;
while it.valid() {
let err_msg: &'static str;
if let Some(SourceRegion { start: _, end: e }) = it.expect_specific_op(OperatorType::RightParen) {
end = Some(e);
break
} else if it.expect_specific_op(OperatorType::Comma).is_some() {
sep = true;
continue
} else if sep {
if let Some(param) = expression(it) {
parameters.push(param);
sep = false;
continue
} else {
err_msg = "a parameter expression for";
}
} else {
err_msg = ", to seperate parameter expressions in";
}
it.simple_error(format!("Expected {} call expression", err_msg));
let (op, SourceRegion { start: _, end: e }) = it.synchronize_on_ops(pred::contextual(
pred::specific_op(OperatorType::LeftParen),
pred::specific_op(OperatorType::RightParen),
pred::specific_op(OperatorType::Comma)
))?;
if op == OperatorType::RightParen {
end = Some(e);
break
} else {
sep = true;
}
}
let source = SourceRegion {
start: left.source.start,
end: end.unwrap_index_with_iterator(it, "Expected ) to end call expression")
};
Some(Expression {
data: ExpressionData::Call { callee: Box::new(left), parameters },
source
})
}
fn expr_cast (left: Expression, it: &mut ParserIterator) -> Option<Expression> {
it.expect_specific_op(OperatorType::Cast)?;
let (as_ty, end) = if let Some(SourceRegion { start: _, end: e }) = it.expect_ignore() {
(None, e)
} else if let Some(texpr) = type_expression(it) {
let end = texpr.source.end;
(Some(Box::new(texpr)), end)
} else {
it.simple_error("Expected _ or type expression to follow cast operator as".to_string());
return None;
};
let source = SourceRegion { start: left.source.start, end };
Some(Expression {
data: ExpressionData::Cast { operand: Box::new(left), as_ty },
source
})
}
struct PrefixParselet {
predicate: fn (&Token) -> bool,
procedure: fn (&mut ParserIterator) -> Option<Expression>,
}
struct InfixParselet {
precedence: usize,
predicate: fn (&Token) -> bool,
procedure: fn (Expression, &mut ParserIterator) -> Option<Expression>,
}
macro_rules! pfx {
( $( ( $pred: expr, $proc: expr ) ), * $(,)? ) => {
&[ $( PrefixParselet { predicate: $pred, procedure: $proc } ), * ]
};
}
macro_rules! ifx {
( $( ( $prec: expr, $pred: expr, $proc: expr ) ), * $(,)? ) => {
&[ $( InfixParselet { precedence: $prec, predicate: $pred, procedure: $proc } ), * ]
};
}
const PREFIX_PARSELETS: &[PrefixParselet] = pfx! [
(|t| t.is_primary(), expr_primary),
(|t| t.is_specific_op(OperatorType::AddressOf), expr_addr_of),
(|t| t.is_specific_op(OperatorType::LeftParen), expr_sem_group),
(|t| t.is_any_op_of(&[OperatorType::LeftBrace, OperatorType::Colon]), expr_compound),
(|t| t.is_any_op_of(UNARY_OPERATORS), expr_unary),
(|t| t.is_specific_op(OperatorType::LeftBracket) || t.is_any_kw_of(&[KeywordType::If, KeywordType::Match]), expr_block),
];
const INFIX_PARSELETS: &[InfixParselet] = ifx! [
(1 , |t| t.is_specific_kw(KeywordType::Else), expr_else),
(10, |t| t.is_specific_op(OperatorType::Dot), expr_member),
(10, |t| t.is_specific_op(OperatorType::LeftBrace), expr_subscript),
(10, |t| t.is_specific_op(OperatorType::LeftParen), expr_call),
(20, |t| t.is_any_op_of(&[OperatorType::LogicalAnd, OperatorType::LogicalOr, OperatorType::LogicalXor]), expr_binary),
(30, |t| t.is_any_op_of(&[OperatorType::LeftAngle, OperatorType::RightAngle, OperatorType::LesserOrEqual, OperatorType::GreaterOrEqual, OperatorType::NotEqual, OperatorType::Equal]), expr_binary),
(40, |t| t.is_any_op_of(&[OperatorType::InclusiveRange, OperatorType::ExclusiveRange]), expr_binary),
(50, |t| t.is_any_op_of(&[OperatorType::Add, OperatorType::Sub, OperatorType::BitwiseAnd, OperatorType::BitwiseOr, OperatorType::BitwiseXor]), expr_binary),
(60, |t| t.is_any_op_of(&[OperatorType::Mul, OperatorType::Div, OperatorType::Rem, OperatorType::BitwiseLeftShift, OperatorType::BitwiseRightShift]), expr_binary),
(70, |t| t.is_specific_op(OperatorType::Cast), expr_cast),
];
fn get_prefix_parselet (token: &Token) -> Option<&PrefixParselet> {
for prefix in PREFIX_PARSELETS {
if (prefix.predicate)(token) {
return Some(prefix);
}
}
None
}
fn get_infix_parselet (token: &Token) -> Option<&InfixParselet> {
for infix in INFIX_PARSELETS {
if (infix.predicate)(token) {
return Some(infix);
}
}
None
}
pub fn complete_partial_expression (mut left: Expression, precedence: usize, it: &mut ParserIterator) -> Option<Expression> {
while it.valid() {
if let Some(infix_parselet) = get_infix_parselet(it.curr()) {
if precedence >= infix_parselet.precedence { break }
left = (infix_parselet.procedure)(left, it)?;
} else {
break
};
}
Some(left)
}
pub fn pratt (precedence: usize, it: &mut ParserIterator) -> Option<Expression> {
if let Some(prefix_parselet) = get_prefix_parselet(it.curr_opt()?) {
complete_partial_expression(
(prefix_parselet.procedure)(it)?,
precedence,
it
)
} else {
it.simple_error("Failed to find semantic match for this token in the context of an expression".to_string());
None
}
}
pub fn expression (it: &mut ParserIterator) -> Option<Expression> {
pratt(0, it)
}