use std::error::Error; use doughlang::{ ast::{ types::{Literal, Path}, visit::{Visit, Walk}, *, }, intern::interned::Interned, lexer::Lexer, parser::{Parser, expr::Prec}, }; use repline::prebaked::{Response, read_and}; fn main() -> Result<(), Box> { read_and("\x1b[34m", "l>", " >", |line| { let ast: Anno = Parser::new(Lexer::new(line)).parse(Prec::MIN)?; let mut to_lisp = ToLisp; let _ = to_lisp.visit(&ast); println!(); Ok(Response::Accept) })?; Ok(()) } #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] struct ToLisp; impl ToLisp { fn bind_op(&self, op: BindOp) -> &'static str { match op { BindOp::Let => "let", BindOp::Type => "type", BindOp::Fn => "fn", BindOp::Mod => "mod", BindOp::Impl => "impl", BindOp::Struct => "struct", BindOp::Enum => "enum", BindOp::For => "for", BindOp::Match => "match", } } fn pat_op(&self, op: PatOp) -> &'static str { match op { PatOp::Pub => "pub", PatOp::Mut => "mut", PatOp::Ref => "ref", PatOp::Ptr => "ptr", PatOp::Rest => "rest", PatOp::RangeEx => "range-ex", PatOp::RangeIn => "range-in", PatOp::Record => "record", PatOp::Tuple => "tuple", PatOp::Slice => "slice", PatOp::ArRep => "ar-rep", PatOp::Typed => "typed", PatOp::TypePrefixed => "type-prefixed", PatOp::Generic => "generic-in", PatOp::Fn => "fn", PatOp::Alt => "alt", } } fn expr_op(&self, op: Op) -> &'static str { match op { Op::Do => "do", Op::As => "cast", Op::Macro => "macro", Op::Block => "block", Op::Array => "array", Op::ArRep => "ar-rep", Op::Group => "group", Op::Tuple => "tuple", Op::Meta => "meta", Op::Try => "try", Op::Index => "index", Op::Call => "call", Op::Pub => "pub", Op::Loop => "loop", Op::Const => "const", Op::Static => "static", Op::Match => "match", Op::If => "if", Op::While => "while", Op::Break => "break", Op::Return => "return", Op::Continue => "continue", Op::Dot => "dot", Op::RangeEx => "range-ex", Op::RangeIn => "range-in", Op::Neg => "neg", Op::Not => "not", Op::Identity => "identity", Op::Refer => "refer", Op::Deref => "deref", Op::Mul => "mul", Op::Div => "div", Op::Rem => "rem", Op::Add => "add", Op::Sub => "sub", Op::Shl => "shl", Op::Shr => "shr", Op::And => "and", Op::Xor => "xor", Op::Or => "or", Op::Lt => "lt", Op::Leq => "leq", Op::Eq => "eq", Op::Neq => "neq", Op::Geq => "geq", Op::Gt => "gt", Op::LogAnd => "log-and", Op::LogXor => "log-xor", Op::LogOr => "log-or", Op::Set => "set", Op::MulSet => "mul-set", Op::DivSet => "div-set", Op::RemSet => "rem-set", Op::AddSet => "add-set", Op::SubSet => "sub-set", Op::ShlSet => "shl-set", Op::ShrSet => "shr-set", Op::AndSet => "and-set", Op::XorSet => "xor-set", Op::OrSet => "or-set", } } } impl<'a> Visit<'a, DefaultTypes> for ToLisp { type Error = (); fn visit_expr(&mut self, expr: &'a Expr) -> Result<(), Self::Error> { match expr { Expr::Omitted => print!("()"), Expr::Id(path) => self.visit_path(path)?, Expr::MetId(id) => print!("`{id}"), Expr::Lit(literal) => self.visit_literal(literal)?, Expr::Use(import) => import.visit_in(self)?, Expr::Bind(bind) => bind.visit_in(self)?, Expr::Make(make) => make.visit_in(self)?, Expr::Op(op, annos) => { print!("({}", self.expr_op(*op)); for anno in annos { print!(" "); anno.visit_in(self)?; } print!(")"); } } Ok(()) } fn visit_macro_id(&mut self, name: &'a Interned<'static, str>) -> Result<(), Self::Error> { print!("{name}"); Ok(()) } fn visit_symbol(&mut self, name: &'a Interned<'static, str>) -> Result<(), Self::Error> { print!("{name}"); Ok(()) } fn visit_path(&mut self, path: &'a Path) -> Result<(), Self::Error> { let Path { parts } = path; print!("(at"); for part in parts { print!(" "); self.visit_symbol(part)?; } print!(")"); Ok(()) } fn visit_literal(&mut self, lit: &'a Literal) -> Result<(), Self::Error> { print!("{lit}"); Ok(()) } fn visit_use(&mut self, item: &'a Use) -> Result<(), Self::Error> { match item { Use::Glob => print!("(use-glob)"), Use::Name(name) => self.visit_symbol(name)?, Use::Alias(name, alias) => print!("(use-alias {name} {alias})"), Use::Path(name, tree) => { print!("(use-path {name} "); tree.visit_in(self)?; print!(")"); } Use::Tree(items) => { print!("(use-tree"); for item in items { print!(" "); item.visit_in(self)?; } print!(")"); } } Ok(()) } fn visit_pat(&mut self, item: &'a Pat) -> Result<(), Self::Error> { match item { Pat::Ignore => print!("(ignore)"), Pat::Never => print!("(never)"), Pat::MetId(id) => print!("(replace {id})"), Pat::Name(name) => print!("{name}"), Pat::Value(literal) => literal.visit_in(self)?, Pat::Op(pat_op, pats) => { print!("({}", self.pat_op(*pat_op)); for pat in pats { print!(" "); pat.visit_in(self)?; } print!(")"); } } Ok(()) } fn visit_bind(&mut self, item: &'a Bind) -> Result<(), Self::Error> { let Bind(op, generics, pattern, exprs) = item; print!("({} ", self.bind_op(*op)); if !generics.is_empty() { print!("(for-some"); for generic in generics { print!(" {generic}"); } print!(") "); } pattern.visit_in(self)?; for expr in exprs { print!(" "); expr.visit_in(self)?; } print!(")"); Ok(()) } fn visit_make(&mut self, item: &'a Make) -> Result<(), Self::Error> { item.children(self) } fn visit_makearm(&mut self, item: &'a MakeArm) -> Result<(), Self::Error> { item.children(self) } }