use std::fmt::Display;
use crate::{
Expression, Program, Statement,
expressions::{ExpressionType, HashMapItem, ImportedItem, InfixOperator, PrefixOperator},
statements::Binding,
types::{FunctionParameterType, Type, TypeVarId},
};
macro_rules! display_expr_ty {
( $( $name: ident => $str: expr ),* ) => {
impl Display for ExpressionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
$(
ExpressionType::$name => $str,
)*
})
}
}
};
}
macro_rules! expr_type {
( $($expr: pat => $ty: ident),* ) => {
impl Expression {
pub fn r#type(&self) -> ExpressionType {
use Expression::*;
match self {
$(
$expr => ExpressionType::$ty,
)*
}
}
}
};
}
impl Display for Expression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Expression as E;
f.write_str(&match self {
E::Identifier(ident) => ident.to_string(),
E::Integer(val) => val.to_string(),
E::Float(val) => val.to_string(),
E::Boolean(val) => val.to_string(),
E::String(val) => format!("\"{val}\""),
E::Char(val) => format!("'{val}'"),
E::Null => "null".to_string(),
E::TypeOf(expr) => format!("typeof {expr}"),
E::Type(ty) => format!("{ty}"),
E::Try(expr) => format!("{expr}?"),
E::Infix {
left,
operator,
right,
} => format!("({left} {operator} {right})"),
E::Prefix { operator, right } => format!("{operator}{right}"),
E::Scope { statements } => format!(
"{{\n{}}}",
statements
.iter()
.map(|stmt| format!("{stmt}\n"))
.collect::<Vec<_>>()
.join(";")
),
E::IfElse {
consequences,
else_consequence,
} => {
return {
let mut first = true;
for (cond, cons) in consequences {
write!(
f,
"{}if {cond}: {cons}",
if first {
first = false;
""
} else {
" else "
}
)?;
}
if let Some(else_con) = else_consequence {
write!(f, " else: {else_con}",)?;
}
Ok(())
};
}
E::Function {
parameters,
return_type,
body,
generics,
} => format!(
"fn{}({}) {return_type}: {body}",
if generics.is_empty() {
"".to_string()
} else {
format!(
"[{}]",
generics
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
)
},
parameters
.iter()
.map(|param| format!(
"{}{} {}",
if param.is_constant { "const " } else { "" },
param.type_def,
param.name
))
.collect::<Vec<_>>()
.join(", "),
),
E::Call {
function,
arguments,
} => format!(
"{function}({})",
arguments
.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join(", ")
),
E::Array { items } => format!(
"[{}]",
items
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
),
E::HashMap { items } => format!(
"#{{ {} }}",
items
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
),
E::Index { left, index } => format!("{left}[{index}]"),
})
}
}
impl Display for Statement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&match self {
Self::Binding(Binding {
ident,
type_annotation,
value,
is_constant,
}) => format!(
"{}{} {} = {};",
if *is_constant { "const " } else { "" },
if let Some(ty_a) = type_annotation {
ty_a.to_string()
} else {
"let".to_string()
},
ident,
value
),
Self::Expression(expr) => format!("{expr};"),
Self::Return(expr) => format!(
"return{}",
match expr {
Some(e) => format!(" {e};"),
None => ";".to_string(),
}
),
Self::Assign { left, value } => format!("{left} = {value};"),
Self::Alias { ident, ty } => format!("type {ident} = {ty};"),
Self::Get {
path_names,
file_module_path: _,
module_name: _,
imported_items,
} => format!(
"get {}{};",
path_names.join("/"),
if imported_items.is_empty() {
String::new()
} else {
format!(
" {{ {} }}",
imported_items
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
)
}
),
Self::Out(stmt) => format!("out {stmt}"),
})
}
}
impl Display for Program {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for s in &self.statements {
f.write_str(&s.to_string())?;
}
Ok(())
}
}
impl Display for InfixOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
InfixOperator::Add => "+",
InfixOperator::Subtract => "-",
InfixOperator::Multiply => "*",
InfixOperator::Divide => "/",
InfixOperator::Remainder => "%",
InfixOperator::Equals => "==",
InfixOperator::NotEquals => "!=",
InfixOperator::Or => "||",
InfixOperator::And => "&&",
InfixOperator::Less => "<",
InfixOperator::LessEq => "<=",
InfixOperator::Greater => ">",
InfixOperator::GreatEq => ">=",
InfixOperator::BitwiseAnd => "&",
InfixOperator::BitwiseOr => "|",
InfixOperator::BitwiseXOr => "^",
InfixOperator::BitShiftRight => ">>",
InfixOperator::BitShiftLeft => "<<",
})
}
}
impl Display for PrefixOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
PrefixOperator::Not => "!",
PrefixOperator::Neg => "-",
PrefixOperator::Deref => "*",
PrefixOperator::AddrOf => "&",
PrefixOperator::BitwiseNot => "~",
})
}
}
impl Display for HashMapItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", self.key, self.value)
}
}
impl Display for TypeVarId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.name)
}
}
impl Display for FunctionParameterType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let constant = if self.is_constant { "const " } else { "" };
write!(f, "{}{}", constant, self.ty)
}
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Type as T;
f.write_str(&match self {
T::Bool => "bool".to_string(),
T::Char => "char".to_string(),
T::Int => "int".to_string(),
T::Float => "float".to_string(),
T::String => "str".to_string(),
T::Null => "null".to_string(),
T::Void => "void".to_string(),
T::Never => "never".to_string(),
T::Unknown => "unknown".to_string(),
T::AsValue(ty) => format!("type[{ty}]"),
T::Nullable(ty) => format!("{ty}?"),
T::Addr(ty) => format!("{ty}*"),
T::Array(ty) => format!("arr[{ty}]"),
T::HashMap { key, value } => format!("map[{key}, {value}]"),
T::Function {
parameters: paramters,
return_type,
generics,
} => format!(
"fn{}({}) -> {return_type}",
if generics.is_empty() {
"".to_string()
} else {
format!(
"[{}]",
generics
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
)
},
paramters
.iter()
.map(|p| p.to_string())
.collect::<Vec<_>>()
.join(", ")
),
T::TypeVar(t) => t.to_string(),
})
}
}
impl Display for ImportedItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}{}",
self.name,
self.as_naming
.clone()
.map(|x| format!(" as {x}"))
.unwrap_or("".to_string())
)
}
}
impl std::ops::Index<usize> for Program {
type Output = Statement;
fn index(&self, index: usize) -> &Self::Output {
&self.statements[index]
}
}
expr_type!(
Identifier(_) => Identifier,
Integer(_) => Integer,
Float(_) => Float,
Boolean(_) => Boolean,
String(_) => String,
Char(_) => Char,
Null => Null,
TypeOf(_) => TypeOf,
Type(_) => Type,
Try(_) => Try,
Infix{..} => Infix,
Prefix{..} => Prefix,
Scope{..} => Scope,
IfElse{..} => IfElse,
Function{..} => Function,
Call{..} => Call,
Array{..} => Array,
HashMap{..} => HashMap,
Index{..} => Index
);
display_expr_ty!(
Identifier => "identifier",
Integer => "integer literal",
Float => "float literal",
Boolean => "boolean literal",
String => "string literal",
Char => "char literal",
Null => "null literal",
TypeOf => "type of",
Type => "exclusive type",
Try => "try",
Infix => "infix",
Prefix => "prefix",
Scope => "scope",
IfElse => "if else",
Function => "function",
Call => "call",
Array => "array literal",
HashMap => "hash-map literal",
Index => "index"
);