cl-ast: Add syntax support for generics

This commit is contained in:
2025-04-22 07:22:44 -04:00
parent 681fbc88d3
commit 8ff17fd475
14 changed files with 124 additions and 36 deletions

View File

@@ -93,6 +93,12 @@ pub enum ItemKind {
Use(Use),
}
/// A list of type variables to introduce
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct Generics {
pub vars: Vec<Sym>,
}
/// An ordered collection of [Items](Item)
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Module {
@@ -128,6 +134,7 @@ pub struct Static {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Function {
pub name: Sym,
pub gens: Generics,
pub sign: TyFn,
pub bind: Pattern,
pub body: Option<Expr>,
@@ -137,6 +144,7 @@ pub struct Function {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Struct {
pub name: Sym,
pub gens: Generics,
pub kind: StructKind,
}
@@ -160,6 +168,7 @@ pub struct StructMember {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Enum {
pub name: Sym,
pub gens: Generics,
pub variants: Option<Vec<Variant>>,
}

View File

@@ -112,6 +112,16 @@ impl Display for ItemKind {
}
}
impl Display for Generics {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Generics { vars } = self;
if !vars.is_empty() {
separate(vars, ", ")(f.delimit_with("<", ">"))?
}
Ok(())
}
}
impl Display for Alias {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, from } = self;
@@ -152,7 +162,7 @@ impl Display for Module {
impl Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, sign: sign @ TyFn { args, rety }, bind, body } = self;
let Self { name, gens, sign: sign @ TyFn { args, rety }, bind, body } = self;
let types = match **args {
TyKind::Tuple(TyTuple { ref types }) => types.as_slice(),
TyKind::Empty => Default::default(),
@@ -170,7 +180,7 @@ impl Display for Function {
};
debug_assert_eq!(bind.len(), types.len());
write!(f, "fn {name} ")?;
write!(f, "fn {name}{gens} ")?;
{
let mut f = f.delimit(INLINE_PARENS);
@@ -193,8 +203,8 @@ impl Display for Function {
impl Display for Struct {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, kind } = self;
write!(f, "struct {name}{kind}")
let Self { name, gens, kind } = self;
write!(f, "struct {name}{gens}{kind}")
}
}
@@ -217,8 +227,8 @@ impl Display for StructMember {
impl Display for Enum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, variants: kind } = self;
write!(f, "enum {name}")?;
let Self { name, gens, variants: kind } = self;
write!(f, "enum {name}{gens}")?;
match kind {
Some(v) => separate(v, ",\n")(f.delimit(SPACED_BRACES)),
None => ";".fmt(f),

View File

@@ -65,6 +65,13 @@ impl WeightOf for ItemKind {
}
}
impl WeightOf for Generics {
fn weight_of(&self) -> usize {
let Self { vars } = self;
vars.iter().map(|v| v.weight_of()).sum()
}
}
impl WeightOf for Module {
fn weight_of(&self) -> usize {
let Self { name, file } = self;
@@ -95,15 +102,15 @@ impl WeightOf for Static {
impl WeightOf for Function {
fn weight_of(&self) -> usize {
let Self { name, sign, bind, body } = self;
name.weight_of() + sign.weight_of() + bind.weight_of() + body.weight_of()
let Self { name, gens, sign, bind, body } = self;
name.weight_of() + gens.weight_of() + sign.weight_of() + bind.weight_of() + body.weight_of()
}
}
impl WeightOf for Struct {
fn weight_of(&self) -> usize {
let Self { name, kind } = self;
name.weight_of() + kind.weight_of()
let Self { name, gens, kind } = self;
name.weight_of() + gens.weight_of() + kind.weight_of()
}
}
@@ -126,8 +133,9 @@ impl WeightOf for StructMember {
impl WeightOf for Enum {
fn weight_of(&self) -> usize {
let Self { name, variants } = self;
let Self { name, gens, variants } = self;
name.weight_of()
+ gens.weight_of()
+ variants
.as_ref()
.map_or(size_of_val(variants), |v| v.weight_of())

View File

@@ -70,6 +70,10 @@ pub trait Fold {
fn fold_item_kind(&mut self, kind: ItemKind) -> ItemKind {
or_fold_item_kind(self, kind)
}
fn fold_generics(&mut self, gens: Generics) -> Generics {
let Generics { vars } = gens;
Generics { vars: vars.into_iter().map(|sym| self.fold_sym(sym)).collect() }
}
fn fold_alias(&mut self, a: Alias) -> Alias {
let Alias { name, from } = a;
Alias { name: self.fold_sym(name), from: from.map(|from| Box::new(self.fold_ty(*from))) }
@@ -96,17 +100,22 @@ pub trait Fold {
Module { name: self.fold_sym(name), file: file.map(|v| self.fold_file(v)) }
}
fn fold_function(&mut self, f: Function) -> Function {
let Function { name, sign, bind, body } = f;
let Function { name, gens, sign, bind, body } = f;
Function {
name: self.fold_sym(name),
gens: self.fold_generics(gens),
sign: self.fold_ty_fn(sign),
bind: self.fold_pattern(bind),
body: body.map(|b| self.fold_expr(b)),
}
}
fn fold_struct(&mut self, s: Struct) -> Struct {
let Struct { name, kind } = s;
Struct { name: self.fold_sym(name), kind: self.fold_struct_kind(kind) }
let Struct { name, gens, kind } = s;
Struct {
name: self.fold_sym(name),
gens: self.fold_generics(gens),
kind: self.fold_struct_kind(kind),
}
}
fn fold_struct_kind(&mut self, kind: StructKind) -> StructKind {
match kind {
@@ -130,9 +139,10 @@ pub trait Fold {
}
}
fn fold_enum(&mut self, e: Enum) -> Enum {
let Enum { name, variants: kind } = e;
let Enum { name, gens, variants: kind } = e;
Enum {
name: self.fold_sym(name),
gens: self.fold_generics(gens),
variants: kind.map(|v| v.into_iter().map(|v| self.fold_variant(v)).collect()),
}
}

View File

@@ -51,6 +51,10 @@ pub trait Visit<'a>: Sized {
fn visit_item_kind(&mut self, kind: &'a ItemKind) {
or_visit_item_kind(self, kind)
}
fn visit_generics(&mut self, gens: &'a Generics) {
let Generics { vars } = gens;
vars.iter().for_each(|name| self.visit_sym(name));
}
fn visit_alias(&mut self, a: &'a Alias) {
let Alias { name, from } = a;
self.visit_sym(name);
@@ -79,8 +83,9 @@ pub trait Visit<'a>: Sized {
}
}
fn visit_function(&mut self, f: &'a Function) {
let Function { name, sign, bind, body } = f;
let Function { name, gens, sign, bind, body } = f;
self.visit_sym(name);
self.visit_generics(gens);
self.visit_ty_fn(sign);
self.visit_pattern(bind);
if let Some(b) = body {
@@ -88,8 +93,9 @@ pub trait Visit<'a>: Sized {
}
}
fn visit_struct(&mut self, s: &'a Struct) {
let Struct { name, kind } = s;
let Struct { name, gens, kind } = s;
self.visit_sym(name);
self.visit_generics(gens);
self.visit_struct_kind(kind);
}
fn visit_struct_kind(&mut self, kind: &'a StructKind) {
@@ -102,8 +108,9 @@ pub trait Visit<'a>: Sized {
self.visit_ty(ty);
}
fn visit_enum(&mut self, e: &'a Enum) {
let Enum { name, variants: kind } = e;
let Enum { name, gens, variants: kind } = e;
self.visit_sym(name);
self.visit_generics(gens);
if let Some(variants) = kind {
variants.iter().for_each(|v| self.visit_variant(v))
}