use std::fmt;
use crate::compiler::state::{TypeInfo, TypeState};
use crate::compiler::{
Context, Expression, TypeDef,
expression::{Expr, Resolved},
};
use crate::value::Kind;
#[derive(Debug, Clone, PartialEq)]
pub struct Block {
inner: Vec<Expr>,
new_scope: bool,
}
impl Block {
#[must_use]
fn new(inner: Vec<Expr>, new_scope: bool) -> Self {
Self { inner, new_scope }
}
#[must_use]
pub fn new_scoped(inner: Vec<Expr>) -> Self {
Self::new(inner, true)
}
#[must_use]
pub fn new_inline(inner: Vec<Expr>) -> Self {
Self::new(inner, false)
}
#[must_use]
pub fn into_inner(self) -> Vec<Expr> {
self.inner
}
#[must_use]
pub fn exprs(&self) -> &Vec<Expr> {
&self.inner
}
}
impl Expression for Block {
fn resolve(&self, ctx: &mut Context) -> Resolved {
let (last, other) = self.inner.split_last().expect("at least one expression");
other
.iter()
.try_for_each(|expr| expr.resolve(ctx).map(|_| ()))?;
last.resolve(ctx)
}
fn type_info(&self, state: &TypeState) -> TypeInfo {
let parent_locals = state.local.clone();
let mut state = state.clone();
let mut result = TypeDef::null();
let mut fallible = false;
let mut returns = Kind::never();
let mut after_never_expression = false;
for expr in &self.inner {
result = expr.apply_type_info(&mut state);
if !after_never_expression && result.is_fallible() {
fallible = true;
}
if result.is_never() {
after_never_expression = true;
}
returns.merge_keep(result.returns().clone(), false);
}
if self.new_scope {
state.local = parent_locals.apply_child_scope(state.local);
}
TypeInfo::new(state, result.maybe_fallible(fallible).with_returns(returns))
}
}
impl fmt::Display for Block {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("{\n")?;
let mut iter = self.inner.iter().peekable();
while let Some(expr) = iter.next() {
f.write_str("\t")?;
expr.fmt(f)?;
if iter.peek().is_some() {
f.write_str("\n")?;
}
}
f.write_str("\n}")
}
}