examples: add silly to-lisp converter that doesn't produce any actual lisp
This commit is contained in:
257
examples/to-lisp.rs
Normal file
257
examples/to-lisp.rs
Normal file
@@ -0,0 +1,257 @@
|
||||
use std::error::Error;
|
||||
|
||||
use doughlang::{
|
||||
ast::{
|
||||
visit::{Visit, Walk},
|
||||
*,
|
||||
},
|
||||
lexer::Lexer,
|
||||
parser::{Parser, expr::Prec},
|
||||
};
|
||||
|
||||
use repline::prebaked::{Response, read_and};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
read_and("\x1b[34m", "l>", " >", |line| {
|
||||
let ast: Anno<Expr> = 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::Const => "const",
|
||||
BindOp::Static => "static",
|
||||
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::Tuple => "tuple",
|
||||
PatOp::Slice => "slice",
|
||||
PatOp::ArRep => "ar-rep",
|
||||
PatOp::Typed => "typed",
|
||||
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::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> for ToLisp {
|
||||
type Error = ();
|
||||
|
||||
fn visit(&mut self, walk: &'a impl Walk<'a>) -> Result<(), Self::Error> {
|
||||
walk.visit_in(self)
|
||||
}
|
||||
|
||||
fn visit_expr<A: Annotation>(&mut self, expr: &'a Expr<A>) -> Result<(), Self::Error> {
|
||||
match expr {
|
||||
Expr::Omitted => print!("()"),
|
||||
Expr::Id(path) => path.visit_in(self)?,
|
||||
Expr::MetId(id) => print!("`{id}"),
|
||||
Expr::Lit(literal) => literal.visit_in(self)?,
|
||||
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_ident(&mut self, name: &'a 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!(" ");
|
||||
part.visit_in(self)?;
|
||||
}
|
||||
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) => name.visit_in(self)?,
|
||||
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::Path(path) => path.visit_in(self)?,
|
||||
Pat::NamedStruct(path, pat) => {
|
||||
print!("(struct-pat ");
|
||||
path.visit_in(self)?;
|
||||
print!(" ");
|
||||
pat.visit_in(self)?;
|
||||
print!(")")
|
||||
}
|
||||
Pat::NamedTuple(path, pat) => {
|
||||
print!("(named ");
|
||||
path.visit_in(self)?;
|
||||
print!(" ");
|
||||
pat.visit_in(self)?;
|
||||
print!(")")
|
||||
}
|
||||
Pat::Lit(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<A: Annotation>(&mut self, item: &'a Bind<A>) -> 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<A: Annotation>(&mut self, item: &'a Make<A>) -> Result<(), Self::Error> {
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_makearm<A: Annotation>(&mut self, item: &'a MakeArm<A>) -> Result<(), Self::Error> {
|
||||
item.children(self)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user