use crate::util::BoolAsOption;
use crate::common::{ OperatorType, KeywordType, UNARY_POWER };
use crate::tracking::SourceRegion;
use super::iterator::{ ParserIterator, UnwrapIndexWithIterator };
use super::ast::{ ExpressionData, Expression, StatementData, Statement, StructField, EnumField, NamedExpressionPattern, Pattern, PatternData, Block, ExpressionStatement, ConditionalBranch, ConditionalBlock, MatchBranch, MatchBlock };
use super::pred;
use super::texpr::type_expression;
use super::expr::{ expression, complete_partial_expression };
use super::patt::pattern;
use super::stmt::statement;
pub fn block (it: &mut ParserIterator) -> Option<(Block, SourceRegion)> {
let start = if let Some(SourceRegion { start, end: _ }) = it.expect_specific_op(OperatorType::LeftBracket) {
start
} else {
it.simple_error("Expected { to open block".to_string());
if let Some((_, SourceRegion { start, end: _ })) = it.synchronize_on_ops_with_limit(1, pred::specific_op(OperatorType::LeftBracket)) {
start
} else {
return None;
}
};
let mut statements = Vec::new();
let mut end = None;
let mut sep = true;
while it.valid() {
let err_msg;
if let Some(SourceRegion { start: _, end: e }) = it.expect_specific_op(OperatorType::RightBracket) {
end = Some(e);
break
} else if it.expect_specific_op(OperatorType::Semi).is_some() {
sep = true;
continue;
} else if sep {
if let Some(stmt) = statement(it) {
if stmt.requires_semi() {
sep = false;
}
statements.push(stmt);
continue;
} else {
err_msg = "statement or terminator expression in";
}
} else {
err_msg = "; to separate statements or } to end";
}
it.simple_error(format!("Expected {} block", err_msg));
if it.synchronize(pred::contextual(
pred::specific_op(OperatorType::LeftBracket),
pred::specific_op(OperatorType::RightBracket),
pred::or(
pred::any_kw,
pred::specific_op(OperatorType::Semi),
)
)) {
if let Some((op, SourceRegion { start: _, end: e })) = it.expect_any_op() {
if op == OperatorType::RightBracket {
end = Some(e);
break
} else if op == OperatorType::Semi {
sep = true;
}
} else {
sep = true;
}
} else {
return None;
}
}
let source = SourceRegion { start, end: end.unwrap_index_with_iterator(it, "Expected } to end block") };
let terminator = if !sep && statements.last().and_then(|stmt| stmt.data.evaluates_to_expression().as_option()).is_some() {
if let ExpressionStatement::Expression(expr) = statements.pop()?.convert_to_expression() {
Some(expr)
} else {
panic!("Unknown internal error converting final statement of block to expression terminator");
}
} else {
None
};
Some((
Block {
statements,
terminator
},
source
))
}
pub fn block_expr_stmt (it: &mut ParserIterator) -> Option<ExpressionStatement> {
let (block, source) = block(it)?;
if block.evaluates_to_expression() {
let left = Expression {
data: ExpressionData::Block(Box::new(block)),
source
};
Some(ExpressionStatement::Expression(
complete_partial_expression(
left,
UNARY_POWER,
it
)?
))
} else {
Some(ExpressionStatement::Statement(Statement {
data: StatementData::Block(block),
source
}))
}
}
fn conditional_branch (it: &mut ParserIterator) -> Result<(ConditionalBranch, SourceRegion), &'static str> {
let err_msg;
if let Some(SourceRegion { start, end: _ }) = it.expect_specific_kw(KeywordType::If) {
if let Some(condition) = expression(it) {
if let Some((body, SourceRegion { start: _, end })) = block(it) {
return Ok((
ConditionalBranch {
condition,
body
},
SourceRegion { start, end }
))
} else {
err_msg = "body block for conditional branch";
}
} else {
err_msg = "predicate expression for conditional branch";
}
} else {
err_msg = "if to start conditional branch";
}
Err(err_msg)
}
pub fn conditional_block (it: &mut ParserIterator) -> Option<ExpressionStatement> {
match conditional_branch(it) {
Ok((if_branch, SourceRegion { start, mut end })) => {
let mut else_if_branches = Vec::new();
let mut else_branch = None;
while it.valid() {
if it.expect_specific_kw(KeywordType::Else).is_some() {
if it.curr_opt().and_then(|t| t.is_specific_kw(KeywordType::If).as_option()).is_some() {
match conditional_branch(it) {
Ok((branch, SourceRegion { start: _, end: e })) => {
else_if_branches.push(branch);
end = e;
},
Err(msg) => {
it.simple_error(format!("Expected {} in conditional statement", msg));
it.synchronize(pred::or(
pred::any_kw,
pred::specific_op(OperatorType::Semi)
));
end = it.index;
}
}
} else {
if let Some((block, SourceRegion { start: _, end: e })) = block(it) {
else_branch = Some(block);
end = e;
} else {
it.simple_error("Expected body block to follow unqualified else keyword in conditional statement".to_string());
}
break
}
} else {
break
}
}
let conditional = ConditionalBlock {
if_branch,
else_if_branches,
else_branch
};
let source = SourceRegion { start, end };
if conditional.evaluates_to_expression() {
Some(ExpressionStatement::Expression(
complete_partial_expression(
Expression {
data: ExpressionData::Conditional(Box::new(conditional)),
source
},
UNARY_POWER,
it
)?
))
} else {
Some(ExpressionStatement::Statement(Statement {
data: StatementData::Conditional(conditional),
source
}))
}
},
Err(msg) => {
it.simple_error(format!("Expected {} in conditional statement", msg));
None
}
}
}
pub fn match_block (it: &mut ParserIterator) -> Option<ExpressionStatement> {
let SourceRegion { start, end: _ } = it.expect_specific_kw(KeywordType::Match)?;
let operand = expression(it);
if operand.is_none() {
it.simple_error("Expected operand expression to follow match keyword".to_string());
}
if it.expect_specific_op(OperatorType::LeftBracket).is_none() {
it.simple_error("Expected { to open match block".to_string());
it.synchronize_on_ops_with_limit(1, pred::specific_op(OperatorType::LeftBracket))?;
}
let mut branches = Vec::new();
let mut end = None;
let mut sep = true;
while it.valid() {
let err_msg;
if let Some(SourceRegion { start: _, end: e }) = it.expect_specific_op(OperatorType::RightBracket) {
end = Some(e);
break
} else if it.expect_specific_op(OperatorType::Comma).is_some() {
sep = true;
continue
} else if sep {
if let Some(condition) = named_expression_pattern(it) {
if it.expect_specific_op(OperatorType::WideArrow).is_some() {
if let Some(body) = statement(it) {
sep = false;
branches.push(MatchBranch {
condition,
body
});
continue
} else {
err_msg = "statement for body of branch in";
}
} else {
err_msg = "=> to separate condition pattern and body of branch in";
}
} else {
err_msg = "condition pattern for branch of";
}
} else {
err_msg = ", to separate branches or } to end";
}
it.simple_error(format!("Expected {} match statement", err_msg));
let (op, SourceRegion { start: _, end: e }) = it.synchronize_on_ops(pred::contextual(
pred::specific_op(OperatorType::LeftBracket),
pred::specific_op(OperatorType::RightBracket),
pred::specific_op(OperatorType::Comma)
))?;
if op == OperatorType::RightBracket {
end = Some(e);
break
} else {
sep = true;
}
}
let match_block = MatchBlock {
operand: operand?,
branches
};
let source = SourceRegion {
start,
end: end.unwrap_index_with_iterator(it, "Expected } to end match statement")
};
if match_block.evaluates_to_expression() {
Some(ExpressionStatement::Expression(
complete_partial_expression(
Expression {
data: ExpressionData::Match(Box::new(match_block)),
source
},
UNARY_POWER,
it
)?
))
} else {
Some(ExpressionStatement::Statement(Statement {
data: StatementData::Match(match_block),
source
}))
}
}
pub fn named_expression_pattern (it: &mut ParserIterator) -> Option<NamedExpressionPattern> {
if it.curr_opt()?.is_ident() {
if let Some(next) = it.peek_next() {
if next.is_specific_op(OperatorType::Assign) {
let (name, source) = it.expect_ident()?;
it.advance();
return if let Some(expression ) = expression(it) {
Some(NamedExpressionPattern::NamedExpression { name, expression })
} else {
it.simple_error("Expected value expression to follow = in tuple pattern field".to_string());
it.synchronize(pred::contextual(
pred::specific_op(OperatorType::LeftParen),
pred::specific_op(OperatorType::RightParen),
pred::specific_op(OperatorType::Comma)
));
Some(NamedExpressionPattern::Pattern(Pattern {
data: PatternData::Identifier(name),
source
}))
};
}
}
}
return Some(NamedExpressionPattern::Pattern(pattern(it)?));
}
pub fn struct_ty_body (it: &mut ParserIterator) -> Option<(Vec<StructField>, Option<usize>)> {
if !it.expect_specific_op(OperatorType::LeftBrace).is_some() {
it.simple_error("Expected [ to begin structural type body".to_string());
it.synchronize_on_ops_with_limit(1, pred::specific_op(OperatorType::LeftBrace))?;
}
let mut fields: Vec<StructField> = 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 it.expect_specific_op(OperatorType::Comma).is_some() {
sep = true;
continue
} else if sep {
if let Some((name, _)) = it.expect_ident() {
if let Some(_) = it.expect_specific_op(OperatorType::Colon) {
if let Some(ty) = type_expression(it) {
fields.push(StructField { name, ty });
sep = false;
continue;
} else {
err_msg = "a type for field in";
}
} else {
err_msg = ": to separate field name and value in";
}
} else {
err_msg = "a name for field in";
}
} else {
err_msg = ", to separate fields or ] to end";
}
it.simple_error(format!("Expected {} structural type body", 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((fields, end))
}
pub fn enum_ty_body (it: &mut ParserIterator) -> Option<(Vec<EnumField>, Option<usize>)> {
if !it.expect_specific_op(OperatorType::LeftBrace).is_some() {
it.simple_error("Expected [ to begin structural type body".to_string());
it.synchronize_on_ops_with_limit(1, pred::specific_op(OperatorType::LeftBrace))?;
}
let mut fields: Vec<EnumField> = 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 it.expect_specific_op(OperatorType::Comma).is_some() {
sep = true;
continue
} else if sep {
if let Some((name, _)) = it.expect_ident() {
if let Some(_) = it.expect_specific_op(OperatorType::Assign) {
if let Some(val) = expression(it) {
fields.push(EnumField { name, value: Some(val) });
sep = false;
continue;
} else {
err_msg = "a value for field in";
}
} else {
fields.push(EnumField { name, value: None });
sep = false;
continue;
}
} else {
err_msg = "a name for field in";
}
} else {
err_msg = ", to separate fields or ] to end";
}
it.simple_error(format!("Expected {} enum type body", 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((fields, end))
}
pub fn sum_ty_body (it: &mut ParserIterator) -> Option<(Vec<StructField>, Option<usize>)> {
if !it.expect_specific_op(OperatorType::LeftBrace).is_some() {
it.simple_error("Expected [ to begin anonymous sum type expression field set".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 it.expect_specific_op(OperatorType::Comma).is_some() {
sep = true;
continue
} else if sep {
if let Some((name, _)) = it.expect_ident() {
if let Some(_) = it.expect_specific_op(OperatorType::Colon) {
if let Some(ty) = type_expression(it) {
fields.push(StructField { name, ty });
sep = false;
continue;
} else {
err_msg = "a type for field in";
}
} else {
err_msg = ": to separate field name and value in";
}
} else {
err_msg = "a name for field in";
}
} else {
err_msg = ", to separate fields or ] to end";
}
it.simple_error(format!("Expected {} anonymous sum type expression", 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((fields, end))
}