doughlang: symbol interning and AST reparameterization

- intern: Add interners from cl-intern

- ast:
- Break AST into ternimals (AstTypes) and nonterminals (Expr, Pat, Bind, Make, Use)
- Make AST generic over terminals (except operators, for now)
This commit is contained in:
2026-01-06 04:57:15 -05:00
parent e4c008bd4b
commit 2be73d2660
17 changed files with 952 additions and 592 deletions

View File

@@ -2,9 +2,9 @@ use std::error::Error;
use doughlang::{
ast::{
visit::{Visit, Walk},
*,
types::{Literal, Path}, visit::{Visit, Walk}, *
},
intern::interned::Interned,
lexer::Lexer,
parser::{Parser, expr::Prec},
};
@@ -126,19 +126,15 @@ impl ToLisp {
}
}
impl<'a> Visit<'a> for ToLisp {
impl<'a> Visit<'a, DefaultTypes> 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> {
fn visit_expr(&mut self, expr: &'a Expr) -> Result<(), Self::Error> {
match expr {
Expr::Omitted => print!("()"),
Expr::Id(path) => path.visit_in(self)?,
Expr::Id(path) => self.visit_path(path)?,
Expr::MetId(id) => print!("`{id}"),
Expr::Lit(literal) => literal.visit_in(self)?,
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)?,
@@ -155,7 +151,12 @@ impl<'a> Visit<'a> for ToLisp {
Ok(())
}
fn visit_ident(&mut self, name: &'a str) -> Result<(), Self::Error> {
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(())
}
@@ -165,7 +166,7 @@ impl<'a> Visit<'a> for ToLisp {
print!("(at");
for part in parts {
print!(" ");
part.visit_in(self)?;
self.visit_symbol(part)?;
}
print!(")");
Ok(())
@@ -179,7 +180,7 @@ impl<'a> Visit<'a> for ToLisp {
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::Name(name) => self.visit_symbol(name)?,
Use::Alias(name, alias) => print!("(use-alias {name} {alias})"),
Use::Path(name, tree) => {
print!("(use-path {name} ");
@@ -198,7 +199,7 @@ impl<'a> Visit<'a> for ToLisp {
Ok(())
}
fn visit_pat<A: Annotation>(&mut self, item: &'a Pat<A>) -> Result<(), Self::Error> {
fn visit_pat(&mut self, item: &'a Pat) -> Result<(), Self::Error> {
match item {
Pat::Ignore => print!("(ignore)"),
Pat::Never => print!("(never)"),
@@ -217,7 +218,7 @@ impl<'a> Visit<'a> for ToLisp {
Ok(())
}
fn visit_bind<A: Annotation>(&mut self, item: &'a Bind<A>) -> Result<(), Self::Error> {
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() {
@@ -236,11 +237,11 @@ impl<'a> Visit<'a> for ToLisp {
Ok(())
}
fn visit_make<A: Annotation>(&mut self, item: &'a Make<A>) -> Result<(), Self::Error> {
fn visit_make(&mut self, item: &'a Make) -> Result<(), Self::Error> {
item.children(self)
}
fn visit_makearm<A: Annotation>(&mut self, item: &'a MakeArm<A>) -> Result<(), Self::Error> {
fn visit_makearm(&mut self, item: &'a MakeArm) -> Result<(), Self::Error> {
item.children(self)
}
}