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