use core::fmt; #[allow(unused)] #[derive(Debug, Clone)] pub enum CompilerError { UnexpectedToken(String), UnexpectedEndOfInput, UnexpectedCharacter(char), Undefined(Name), InvalidSyntax(String), Generic(String), UnknownType, TypeMismatch(TypeId, TypeId), Unimplemented(String), } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Name { pub name: String, pub namespace: Option, } #[derive(Debug, Clone)] pub struct Program { pub declarations: Vec, } #[allow(unused)] #[derive(Debug, Clone)] pub enum Declaration { Function { name: String, return_type: TypeId, params: Vec, body: Block, }, Variable { var: Variable, init: Option, is_const: bool, }, Dependency(Dependency), Struct { name: Name, fields: Vec, }, } #[derive(Debug, Clone)] pub struct Dependency { pub name: String, pub path: String, } #[allow(unused)] #[derive(Debug, Clone, PartialEq)] pub enum TypeId { U8, U16, U32, I8, I16, I32, Bool, Char, Void, Ptr(Box), Ref(Box), Tuple(Vec), Array { r#type: Box, size: usize, }, UnknownCustom { name: Name, generics: Vec, }, Struct { name: Name, fields: Vec, generics: Vec, }, } impl TypeId { pub fn size(&self) -> usize { match self { Self::U8 => 1, Self::U16 => 2, Self::U32 => 4, Self::I8 => 1, Self::I16 => 2, Self::I32 => 4, Self::Bool => 1, Self::Char => 1, Self::Void => 0, Self::Ptr(t) => t.size(), Self::Ref(t) => t.size(), Self::Tuple(types) => types.iter().map(|t| t.size()).sum(), Self::Array { r#type, size } => r#type.size() * size, Self::UnknownCustom { .. } => 1, /* TODO: calculate type size during */ // semantic analysis Self::Struct { fields, .. } => fields.iter().map(|t| t.size()).sum(), } } } impl fmt::Display for TypeId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::U8 => write!(f, "u8"), Self::U16 => write!(f, "u16"), Self::U32 => write!(f, "u32"), Self::I8 => write!(f, "i8"), Self::I16 => write!(f, "i16"), Self::I32 => write!(f, "i32"), Self::Bool => write!(f, "bool"), Self::Char => write!(f, "char"), Self::Void => write!(f, "void"), Self::Ptr(t) => write!(f, "*{}", t), Self::Ref(t) => write!(f, "&{}", t), Self::Tuple(elems) => write!( f, "({})", elems .iter() .map(|t| t.to_string()) .collect::>() .join(", ") ), Self::Array { r#type, size } => write!(f, "[{}; {}]", r#type, size), Self::UnknownCustom { name, generics } => { write!( f, "{}<{}>", name, generics .iter() .map(|t| t.to_string()) .collect::>() .join(", ") ) } Self::Struct { name, fields, generics, } => write!( f, "struct<{}> {} {{{}}}", generics .iter() .map(|t| t.to_string()) .collect::>() .join(", "), name, fields .iter() .map(|t| t.to_string()) .collect::>() .join(", ") ), } } } pub type Block = Vec; #[allow(unused)] #[derive(Debug, Clone, PartialEq)] pub struct Variable { pub name: String, pub type_id: TypeId, } #[allow(unused)] #[derive(Debug, Clone)] pub enum Statement { Block(Block), Declaration { var: Variable, value: Option, }, Assign { varname: String, operator: AssignmentOperator, value: Expression, }, PtrWrite { ptr: Expression, value: Expression, }, Expression { expr: Expression, }, If { condition: Expression, then_stmt: Block, else_stmt: Block, }, While { condition: Expression, body: Vec, }, Loop(Block), Defer(Call), Break, Continue, Return(Option), } #[derive(Debug, Clone)] pub enum ConstExpr { Number(i32), String(String), } impl fmt::Display for ConstExpr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { ConstExpr::Number(n) => write!(f, "{}", n), ConstExpr::String(s) => write!(f, "\"{}\"", s), } } } #[allow(unused)] #[derive(Debug, Clone)] pub enum Expression { Empty, Binary { op: BinaryOperator, left: Box, right: Box, // Post-Semantic Analysis type_id: Option, }, Unary { op: UnaryOperator, operand: Box, // Post-Semantic Analysis type_id: Option, }, UnaryPostfix { op: UnaryOperator, operand: Box, // Post-Semantic Analysis type_id: Option, }, Variable { name: Name, expr_type: Option, }, TypeCast { expr: Box, target_type: TypeId, // Post-Semantic Analysis type_id: Option, }, IndexAccess { expr: Box, index: Box, // Post-Semantic Analysis type_id: Option, }, MemberAccess { expr: Box, field_name: Name, // Post-Semantic Analysis type_id: Option, }, Call { func: Call, // Post-Semantic Analysis type_id: Option, }, Number { value: isize, // Post-Semantic Analysis type_id: Option, }, StringLiteral(String), CharLiteral(char), ArrayLiteral { elements: Vec, type_id: Option, }, StructLiteral { name: Name, fields: Vec<(Name, Expression)>, type_id: Option, }, } #[derive(Debug, Clone)] pub struct Call { pub name: Name, pub args: Vec, } impl Expression { pub fn is_pure(&self) -> bool { match self { Expression::Number { .. } => true, Expression::StringLiteral(_) => true, Expression::CharLiteral(_) => true, Expression::Call { .. } => false, Expression::Binary { left, right, .. } => left.is_pure() && right.is_pure(), Expression::Unary { operand, .. } => operand.is_pure(), Expression::UnaryPostfix { operand, .. } => operand.is_pure(), Expression::Empty => true, Expression::Variable { .. } => true, Expression::TypeCast { expr, .. } => expr.is_pure(), Expression::IndexAccess { expr, index, .. } => { expr.is_pure() && index.is_pure() } Expression::MemberAccess { expr, .. } => expr.is_pure(), Expression::ArrayLiteral { elements, .. } => { elements.iter().all(|element| element.is_pure()) } Expression::StructLiteral { fields, .. } => { fields.iter().all(|(_, expr)| expr.is_pure()) } } } pub fn type_id(&self) -> Result { match self { Expression::Number { type_id, .. } => { type_id.clone().ok_or(CompilerError::UnknownType) } Expression::StringLiteral(_) => Ok(TypeId::Ptr(Box::new(TypeId::Char))), Expression::CharLiteral(_) => Ok(TypeId::Char), Expression::Call { type_id, .. } => { type_id.clone().ok_or(CompilerError::UnknownType) } Expression::Binary { type_id, .. } => { type_id.clone().ok_or(CompilerError::UnknownType) } Expression::Unary { type_id, .. } => { type_id.clone().ok_or(CompilerError::UnknownType) } Expression::UnaryPostfix { type_id, .. } => { type_id.clone().ok_or(CompilerError::UnknownType) } Expression::Empty => Ok(TypeId::Void), Expression::Variable { expr_type, .. } => { expr_type.clone().ok_or(CompilerError::UnknownType) } Expression::TypeCast { type_id, .. } => { type_id.clone().ok_or(CompilerError::UnknownType) } Expression::IndexAccess { expr, .. } => expr.type_id(), Expression::MemberAccess { expr, .. } => expr.type_id(), Expression::ArrayLiteral { elements, .. } => { let element_type = elements .first() .map_or(TypeId::Void, |e| e.type_id().unwrap_or(TypeId::Void)); Ok(TypeId::Array { r#type: Box::new(element_type), size: elements.len(), }) } Expression::StructLiteral { name, fields, .. } => { let fields = fields .iter() .map(|(_, expr)| expr.type_id()) .collect::, _>>()?; Ok(TypeId::Struct { name: name.clone(), fields, generics: Vec::new(), }) } } } } #[derive(Debug, Clone, PartialEq)] pub enum AssignmentOperator { Assign, AddAssign, SubAssign, MulAssign, DivAssign, ModAssign, AndAssign, OrAssign, XorAssign, LeftShiftAssign, RightShiftAssign, } #[allow(unused)] #[derive(Debug, Clone, PartialEq)] pub enum BinaryOperator { // arithmetic Add, Sub, Mul, Div, Mod, // comparison Equal, NotEqual, LessThan, GreaterThan, LessOrEqual, GreaterOrEqual, // bitwise BitwiseAnd, BitwiseOr, BitwiseXor, // logical LogicalAnd, LogicalOr, // shift LeftShift, RightShift, } impl fmt::Display for BinaryOperator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Add => write!(f, "+"), Self::Sub => write!(f, "-"), Self::Mul => write!(f, "*"), Self::Div => write!(f, "/"), Self::Mod => write!(f, "%"), Self::Equal => write!(f, "=="), Self::NotEqual => write!(f, "!="), Self::LessThan => write!(f, "<"), Self::GreaterThan => write!(f, ">"), Self::LessOrEqual => write!(f, "<="), Self::GreaterOrEqual => write!(f, ">="), Self::BitwiseAnd => write!(f, "&"), Self::BitwiseOr => write!(f, "|"), Self::BitwiseXor => write!(f, "^"), Self::LogicalAnd => write!(f, "&&"), Self::LogicalOr => write!(f, "||"), Self::LeftShift => write!(f, "<<"), Self::RightShift => write!(f, ">>"), } } } #[derive(Debug, Clone, PartialEq)] pub enum UnaryOperator { Plus, Minus, AddressOf, Dereference, BitwiseNot, LogicalNot, Increment, Decrement, SizeOf, } impl fmt::Display for UnaryOperator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Increment => write!(f, "++"), Self::Decrement => write!(f, "--"), Self::Plus => write!(f, "+"), Self::Minus => write!(f, "-"), Self::Dereference => write!(f, "*"), Self::AddressOf => write!(f, "&"), Self::BitwiseNot => write!(f, "~"), Self::LogicalNot => write!(f, "!"), Self::SizeOf => write!(f, "sizeof"), } } }