use ordered_float::OrderedFloat; use salsa::debug::DebugWithDb; // ANCHOR: interned_ids #[salsa::interned] #[derive(Eq, PartialEq, Clone, Hash)] pub struct VariableId { #[return_ref] pub text: String, } #[salsa::interned] #[derive(Eq, PartialEq, Clone, Hash)] pub struct FunctionId { #[return_ref] pub text: String, } // ANCHOR_END: interned_ids // ANCHOR: statements_and_expressions #[salsa::interned] #[derive(Eq, PartialEq, Clone, Hash)] pub enum Statement { /// Defines `fn () = ` Function(Function), /// Defines `print ` Print(Expression), } #[salsa::interned] #[derive(Eq, PartialEq, Clone, Hash)] pub enum Expression { Op(Expression, Op, Expression), Number(OrderedFloat), Variable(VariableId), Call(FunctionId, Vec), } #[derive(Eq, PartialEq, Copy, Clone, Hash, Debug)] pub enum Op { Add, Subtract, Multiply, Divide, } // ANCHOR_END: statements_and_expressions impl DebugWithDb for Function { fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result { f.debug_struct("Function") .field("name", &self.name(db).debug(db)) .field("args", &self.args(db).debug(db)) .field("body", &self.body(db).debug(db)) .finish() } } impl DebugWithDb for Statement { fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result { match self.data(db) { StatementData::Function(a) => DebugWithDb::fmt(a, f, db), StatementData::Print(a) => DebugWithDb::fmt(a, f, db), } } } // ANCHOR: expression_debug_impl impl DebugWithDb for Expression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result { match self.data(db) { ExpressionData::Op(a, b, c) => f .debug_tuple("ExpressionData::Op") .field(&a.debug(db)) // use `a.debug(db)` for interned things .field(&b.debug(db)) .field(&c.debug(db)) .finish(), ExpressionData::Number(a) => { f.debug_tuple("Number") .field(a) // use just `a` otherwise .finish() } ExpressionData::Variable(a) => f.debug_tuple("Variable").field(&a.debug(db)).finish(), ExpressionData::Call(a, b) => f .debug_tuple("Call") .field(&a.debug(db)) .field(&b.debug(db)) .finish(), } } } // ANCHOR_END: expression_debug_impl impl DebugWithDb for FunctionId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result { write!(f, "{:?}", self.text(db)) } } impl DebugWithDb for VariableId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn crate::Db) -> std::fmt::Result { write!(f, "{:?}", self.text(db)) } } // ANCHOR: op_debug_impl impl DebugWithDb for Op { fn fmt(&self, f: &mut std::fmt::Formatter<'_>, _db: &dyn crate::Db) -> std::fmt::Result { write!(f, "{:?}", self) } } // ANCHOR: op_debug_impl impl DebugWithDb for Diagnostic { fn fmt(&self, f: &mut std::fmt::Formatter<'_>, _db: &dyn crate::Db) -> std::fmt::Result { write!(f, "{:?}", self) } } // ANCHOR: functions #[salsa::entity] pub struct Function { #[id] name: FunctionId, args: Vec, body: Expression, } // ANCHOR_END: functions // ANCHOR: diagnostic #[salsa::accumulator] pub struct Diagnostics(Diagnostic); #[derive(Clone, Debug)] pub struct Diagnostic { pub position: usize, pub message: String, } // ANCHOR_END: diagnostic