use super::*;
pub trait Visitor<'ast> {
fn visit_ctor(&mut self, ctor: &'ast Ctor) {
accept_ctor(ctor, self);
}
fn visit_service(&mut self, service: &'ast Service) {
accept_service(service, self);
}
fn visit_type(&mut self, r#type: &'ast Type) {
accept_type(r#type, self);
}
fn visit_vector_type_decl(&mut self, item_type_decl: &'ast TypeDecl) {
accept_type_decl(item_type_decl, self);
}
fn visit_array_type_decl(&mut self, item_type_decl: &'ast TypeDecl, _len: u32) {
accept_type_decl(item_type_decl, self);
}
fn visit_map_type_decl(
&mut self,
key_type_decl: &'ast TypeDecl,
value_type_decl: &'ast TypeDecl,
) {
accept_type_decl(key_type_decl, self);
accept_type_decl(value_type_decl, self);
}
fn visit_optional_type_decl(&mut self, optional_type_decl: &'ast TypeDecl) {
accept_type_decl(optional_type_decl, self);
}
fn visit_result_type_decl(
&mut self,
ok_type_decl: &'ast TypeDecl,
err_type_decl: &'ast TypeDecl,
) {
accept_type_decl(ok_type_decl, self);
accept_type_decl(err_type_decl, self);
}
fn visit_primitive_type_id(&mut self, _primitive_type_id: PrimitiveType) {}
fn visit_user_defined_type_id(&mut self, _user_defined_type_id: &'ast str) {}
fn visit_ctor_func(&mut self, func: &'ast CtorFunc) {
accept_ctor_func(func, self);
}
fn visit_service_func(&mut self, func: &'ast ServiceFunc) {
accept_service_func(func, self);
}
fn visit_service_event(&mut self, event: &'ast ServiceEvent) {
accept_service_event(event, self);
}
fn visit_func_param(&mut self, func_param: &'ast FuncParam) {
accept_func_param(func_param, self);
}
fn visit_func_output(&mut self, func_output: &'ast TypeDecl) {
accept_type_decl(func_output, self);
}
fn visit_struct_def(&mut self, struct_def: &'ast StructDef) {
accept_struct_def(struct_def, self);
}
fn visit_struct_field(&mut self, struct_field: &'ast StructField) {
accept_struct_field(struct_field, self);
}
fn visit_enum_def(&mut self, enum_def: &'ast EnumDef) {
accept_enum_def(enum_def, self);
}
fn visit_enum_variant(&mut self, enum_variant: &'ast EnumVariant) {
accept_enum_variant(enum_variant, self);
}
}
pub fn accept_program<'ast>(program: &'ast Program, visitor: &mut (impl Visitor<'ast> + ?Sized)) {
if let Some(ctor) = program.ctor() {
visitor.visit_ctor(ctor);
}
for service in program.services() {
visitor.visit_service(service);
}
for r#type in program.types() {
visitor.visit_type(r#type);
}
}
pub fn accept_ctor<'ast>(ctor: &'ast Ctor, visitor: &mut (impl Visitor<'ast> + ?Sized)) {
for func in ctor.funcs() {
visitor.visit_ctor_func(func);
}
}
pub fn accept_ctor_func<'ast>(func: &'ast CtorFunc, visitor: &mut (impl Visitor<'ast> + ?Sized)) {
for param in func.params() {
visitor.visit_func_param(param);
}
}
pub fn accept_service<'ast>(service: &'ast Service, visitor: &mut (impl Visitor<'ast> + ?Sized)) {
for func in service.funcs() {
visitor.visit_service_func(func);
}
for event in service.events() {
visitor.visit_service_event(event);
}
}
pub fn accept_service_func<'ast>(
func: &'ast ServiceFunc,
visitor: &mut (impl Visitor<'ast> + ?Sized),
) {
for param in func.params() {
visitor.visit_func_param(param);
}
visitor.visit_func_output(func.output());
}
pub fn accept_service_event<'ast>(
event: &'ast ServiceEvent,
visitor: &mut (impl Visitor<'ast> + ?Sized),
) {
accept_enum_variant(event, visitor)
}
pub fn accept_func_param<'ast>(
func_param: &'ast FuncParam,
visitor: &mut (impl Visitor<'ast> + ?Sized),
) {
accept_type_decl(func_param.type_decl(), visitor);
}
pub fn accept_type<'ast>(r#type: &'ast Type, visitor: &mut (impl Visitor<'ast> + ?Sized)) {
accept_type_def(r#type.def(), visitor);
}
pub fn accept_type_decl<'ast>(
type_decl: &'ast TypeDecl,
visitor: &mut (impl Visitor<'ast> + ?Sized),
) {
match type_decl {
TypeDecl::Vector(item_type_decl) => {
visitor.visit_vector_type_decl(item_type_decl);
}
TypeDecl::Array { item, len } => {
visitor.visit_array_type_decl(item, *len);
}
TypeDecl::Map { key, value } => {
visitor.visit_map_type_decl(key, value);
}
TypeDecl::Optional(optional_type_decl) => {
visitor.visit_optional_type_decl(optional_type_decl);
}
TypeDecl::Result { ok, err } => {
visitor.visit_result_type_decl(ok, err);
}
TypeDecl::Id(TypeId::Primitive(primitive_type_id)) => {
visitor.visit_primitive_type_id(*primitive_type_id);
}
TypeDecl::Id(TypeId::UserDefined(user_defined_type_id)) => {
visitor.visit_user_defined_type_id(user_defined_type_id);
}
TypeDecl::Def(type_def) => {
accept_type_def(type_def, visitor);
}
}
}
pub fn accept_type_def<'ast>(type_def: &'ast TypeDef, visitor: &mut (impl Visitor<'ast> + ?Sized)) {
match type_def {
TypeDef::Struct(struct_def) => {
visitor.visit_struct_def(struct_def);
}
TypeDef::Enum(enum_def) => {
visitor.visit_enum_def(enum_def);
}
}
}
pub fn accept_struct_def<'ast>(
struct_def: &'ast StructDef,
visitor: &mut (impl Visitor<'ast> + ?Sized),
) {
for field in struct_def.fields() {
visitor.visit_struct_field(field);
}
}
pub fn accept_struct_field<'ast>(
struct_field: &'ast StructField,
visitor: &mut (impl Visitor<'ast> + ?Sized),
) {
accept_type_decl(struct_field.type_decl(), visitor);
}
pub fn accept_enum_def<'ast>(enum_def: &'ast EnumDef, visitor: &mut (impl Visitor<'ast> + ?Sized)) {
for variant in enum_def.variants() {
visitor.visit_enum_variant(variant);
}
}
pub fn accept_enum_variant<'ast>(
enum_variant: &'ast EnumVariant,
visitor: &mut (impl Visitor<'ast> + ?Sized),
) {
if let Some(type_decl) = enum_variant.type_decl().as_ref() {
accept_type_decl(type_decl, visitor);
}
}
#[cfg(test)]
mod tests {
use super::*;
struct ProgramVisitor<'ast> {
services: Vec<&'ast Service>,
types: Vec<&'ast Type>,
}
impl<'ast> Visitor<'ast> for ProgramVisitor<'ast> {
fn visit_service(&mut self, service: &'ast Service) {
self.services.push(service);
}
fn visit_type(&mut self, r#type: &'ast Type) {
self.types.push(r#type);
}
}
#[test]
fn accept_program_works() {
let program = Program::new(
Some(Ctor::new(vec![]).unwrap()),
vec![Service::new(String::default(), vec![], vec![]).unwrap()],
vec![
Type::new(
"Type1".into(),
TypeDef::Struct(StructDef::new(vec![]).unwrap()),
vec![],
),
Type::new(
"Type2".into(),
TypeDef::Enum(EnumDef::new(vec![]).unwrap()),
vec![],
),
],
)
.unwrap();
let mut program_visitor = ProgramVisitor {
services: vec![],
types: vec![],
};
accept_program(&program, &mut program_visitor);
assert!(itertools::equal(
program_visitor.services,
program.services()
));
assert!(itertools::equal(program_visitor.types, program.types()));
}
struct EnumDefVisitor<'ast> {
variants: Vec<&'ast EnumVariant>,
}
impl<'ast> Visitor<'ast> for EnumDefVisitor<'ast> {
fn visit_enum_variant(&mut self, enum_variant: &'ast EnumVariant) {
self.variants.push(enum_variant);
}
}
#[test]
fn accept_enum_def_works() {
let enum_def = EnumDef::new(vec![
EnumVariant::new("Variant1".into(), None, vec![]),
EnumVariant::new(
"Variant2".into(),
Some(TypeDecl::Id(TypeId::Primitive(PrimitiveType::U32))),
vec![],
),
])
.unwrap();
let mut enum_def_visitor = EnumDefVisitor { variants: vec![] };
accept_enum_def(&enum_def, &mut enum_def_visitor);
assert!(itertools::equal(
enum_def_visitor.variants,
enum_def.variants()
));
}
}