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), } #[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), } #[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), Array(Box, usize), Struct { name: Name, fields: Vec }, } 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::Array(t, len) => write!(f, "[{}; {}]", t, len), Self::Struct { name, fields } => { write!(f, "struct {} {{", name)?; for (i, field) in fields.iter().enumerate() { write!(f, "{}: {}", i, field)?; } write!(f, "}}") } } } } 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, 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, }, Variable { name: Name, expr_type: Option, }, Call { func: Call, // Post-Semantic Analysis type_id: Option, }, Number { value: isize, // Post-Semantic Analysis type_id: Option, }, StringLiteral(String), CharLiteral(char), } #[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::Empty => true, Expression::Variable { .. } => true, } } 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::Empty => Ok(TypeId::Void), Expression::Variable { expr_type, .. } => { expr_type.clone().ok_or(CompilerError::UnknownType) } } } } #[allow(unused)] #[derive(Debug, Clone, PartialEq)] pub enum BinaryOperator { Add, Sub, Mul, Div, Eq, Ne, Lt, Gt, Le, Ge, } impl fmt::Display for BinaryOperator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { BinaryOperator::Add => write!(f, "+"), BinaryOperator::Sub => write!(f, "-"), BinaryOperator::Mul => write!(f, "*"), BinaryOperator::Div => write!(f, "/"), BinaryOperator::Eq => write!(f, "=="), BinaryOperator::Ne => write!(f, "!="), BinaryOperator::Lt => write!(f, "<"), BinaryOperator::Gt => write!(f, ">"), BinaryOperator::Le => write!(f, "<="), BinaryOperator::Ge => write!(f, ">="), } } } #[derive(Debug, Clone, PartialEq)] pub enum UnaryOperator { Plus, Minus, Reference, Dereference, } impl fmt::Display for UnaryOperator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { UnaryOperator::Plus => write!(f, "+"), UnaryOperator::Minus => write!(f, "-"), UnaryOperator::Dereference => write!(f, "*"), UnaryOperator::Reference => write!(f, "&"), } } }