diff --git a/compiler/load_internal/src/docs.rs b/compiler/load_internal/src/docs.rs index 55cdca9328..ba2d8ff928 100644 --- a/compiler/load_internal/src/docs.rs +++ b/compiler/load_internal/src/docs.rs @@ -2,10 +2,9 @@ use crate::docs::DocEntry::DetachedDoc; use crate::docs::TypeAnnotation::{Apply, BoundVariable, Function, NoTypeAnn, Record, TagUnion}; use crate::file::LoadedModule; use roc_can::scope::Scope; -use roc_error_macros::todo_abilities; use roc_module::ident::ModuleName; use roc_module::symbol::IdentIds; -use roc_parse::ast::{self, TypeHeader}; +use roc_parse::ast::{self, ExtractSpaces, TypeHeader}; use roc_parse::ast::{AssignedField, Def}; use roc_parse::ast::{CommentOrNewline, TypeDef, ValueDef}; use roc_region::all::Loc; @@ -62,9 +61,13 @@ pub enum TypeAnnotation { fields: Vec, extension: Box, }, + Ability { + members: Vec, + }, Wildcard, NoTypeAnn, } + #[derive(Debug, Clone)] pub enum RecordField { RecordField { @@ -80,6 +83,14 @@ pub enum RecordField { }, } +#[derive(Debug, Clone)] +pub struct AbilityMember { + pub name: String, + pub type_annotation: TypeAnnotation, + pub able_variables: Vec<(String, TypeAnnotation)>, + pub docs: Option, +} + #[derive(Debug, Clone)] pub struct Tag { pub name: String, @@ -264,7 +275,45 @@ fn generate_entry_doc<'a>( (acc, None) } - TypeDef::Ability { .. } => todo_abilities!(), + TypeDef::Ability { + header: TypeHeader { name, vars }, + members, + .. + } => { + let mut type_vars = Vec::new(); + + for var in vars.iter() { + if let Pattern::Identifier(ident_name) = var.value { + type_vars.push(ident_name.to_string()); + } + } + + let members = members + .iter() + .map(|mem| { + let extracted = mem.name.value.extract_spaces(); + let (type_annotation, able_variables) = + ability_member_type_to_docs(mem.typ.value); + + AbilityMember { + name: extracted.item.to_string(), + type_annotation, + able_variables, + docs: comments_or_new_lines_to_docs(extracted.before), + } + }) + .collect(); + + let doc_def = DocDef { + name: name.value.to_string(), + type_annotation: TypeAnnotation::Ability { members }, + type_vars, + docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), + }; + acc.push(DocEntry::DocDef(doc_def)); + + (acc, None) + } }, Def::NotYetImplemented(s) => todo!("{}", s), @@ -352,6 +401,29 @@ fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) -> } } +fn ability_member_type_to_docs( + type_annotation: ast::TypeAnnotation, +) -> (TypeAnnotation, Vec<(String, TypeAnnotation)>) { + match type_annotation { + ast::TypeAnnotation::Where(ta, has_clauses) => { + let ta = type_to_docs(false, ta.value); + let has_clauses = has_clauses + .iter() + .map(|hc| { + let ast::HasClause { var, ability } = hc.value; + ( + var.value.extract_spaces().item.to_string(), + type_to_docs(false, ability.value), + ) + }) + .collect(); + + (ta, has_clauses) + } + _ => (type_to_docs(false, type_annotation), vec![]), + } +} + fn record_field_to_doc( in_func_ann: bool, field: ast::AssignedField<'_, ast::TypeAnnotation>, diff --git a/docs/src/lib.rs b/docs/src/lib.rs index 8076660a74..18bdf0e933 100644 --- a/docs/src/lib.rs +++ b/docs/src/lib.rs @@ -636,6 +636,9 @@ fn type_annotation_to_html(indent_level: usize, buf: &mut String, type_ann: &Typ type_annotation_to_html(next_indent_level, buf, output); } + TypeAnnotation::Ability { members: _ } => { + // TODO(abilities): fill me in + } TypeAnnotation::ObscuredTagUnion => { buf.push_str("[ @.. ]"); } @@ -712,6 +715,7 @@ fn should_be_multiline(type_ann: &TypeAnnotation) -> bool { is_multiline } + TypeAnnotation::Ability { .. } => true, TypeAnnotation::Wildcard => false, TypeAnnotation::NoTypeAnn => false, }