1use crate::{Comments, helpers::function_signature, solang_ext::SafeUnwrap};
2use solang_parser::pt::{
3 ContractDefinition, ContractTy, EnumDefinition, ErrorDefinition, EventDefinition,
4 FunctionDefinition, StructDefinition, TypeDefinition, VariableDefinition,
5};
6use std::ops::Range;
7
8#[derive(Debug, PartialEq)]
10pub struct ParseItem {
11 pub source: ParseSource,
13 pub comments: Comments,
15 pub children: Vec<ParseItem>,
17 pub code: String,
19}
20
21macro_rules! filter_children_fn {
25 ($vis:vis fn $name:ident(&self, $variant:ident) -> $ret:ty) => {
26 $vis fn $name(&self) -> Option<Vec<(&$ret, &Comments, &String)>> {
28 let items = self.children.iter().filter_map(|item| match item.source {
29 ParseSource::$variant(ref inner) => Some((inner, &item.comments, &item.code)),
30 _ => None,
31 });
32 let items = items.collect::<Vec<_>>();
33 if !items.is_empty() {
34 Some(items)
35 } else {
36 None
37 }
38 }
39 };
40}
41
42macro_rules! as_inner_source {
45 ($vis:vis fn $name:ident(&self, $variant:ident) -> $ret:ty) => {
46 $vis fn $name(&self) -> Option<&$ret> {
49 match self.source {
50 ParseSource::$variant(ref inner) => Some(inner),
51 _ => None
52 }
53 }
54 };
55}
56
57impl ParseItem {
58 pub fn new(source: ParseSource) -> Self {
60 Self {
61 source,
62 comments: Default::default(),
63 children: Default::default(),
64 code: Default::default(),
65 }
66 }
67
68 pub fn with_comments(mut self, comments: Comments) -> Self {
70 self.comments = comments;
71 self
72 }
73
74 pub fn with_children(mut self, children: Vec<Self>) -> Self {
76 self.children = children;
77 self
78 }
79
80 pub fn with_code(mut self, source: &str) -> Self {
84 let mut code = source[self.source.range()].to_string();
85
86 if let ParseSource::Function(_) = self.source {
88 code.push(';');
89 }
90
91 self.code = code
93 .lines()
94 .map(|line| line.strip_prefix(" ").unwrap_or(line))
95 .collect::<Vec<_>>()
96 .join("\n");
97 self
98 }
99
100 pub fn filename(&self) -> String {
102 let prefix = match self.source {
103 ParseSource::Contract(ref c) => match c.ty {
104 ContractTy::Contract(_) => "contract",
105 ContractTy::Abstract(_) => "abstract",
106 ContractTy::Interface(_) => "interface",
107 ContractTy::Library(_) => "library",
108 },
109 ParseSource::Function(_) => "function",
110 ParseSource::Variable(_) => "variable",
111 ParseSource::Event(_) => "event",
112 ParseSource::Error(_) => "error",
113 ParseSource::Struct(_) => "struct",
114 ParseSource::Enum(_) => "enum",
115 ParseSource::Type(_) => "type",
116 };
117 let ident = self.source.ident();
118 format!("{prefix}.{ident}.md")
119 }
120
121 filter_children_fn!(pub fn variables(&self, Variable) -> VariableDefinition);
122 filter_children_fn!(pub fn functions(&self, Function) -> FunctionDefinition);
123 filter_children_fn!(pub fn events(&self, Event) -> EventDefinition);
124 filter_children_fn!(pub fn errors(&self, Error) -> ErrorDefinition);
125 filter_children_fn!(pub fn structs(&self, Struct) -> StructDefinition);
126 filter_children_fn!(pub fn enums(&self, Enum) -> EnumDefinition);
127
128 as_inner_source!(pub fn as_contract(&self, Contract) -> ContractDefinition);
129 as_inner_source!(pub fn as_variable(&self, Variable) -> VariableDefinition);
130 as_inner_source!(pub fn as_function(&self, Function) -> FunctionDefinition);
131}
132
133#[derive(Clone, Debug, PartialEq, Eq)]
135#[allow(clippy::large_enum_variant)]
136pub enum ParseSource {
137 Contract(Box<ContractDefinition>),
139 Function(FunctionDefinition),
141 Variable(VariableDefinition),
143 Event(EventDefinition),
145 Error(ErrorDefinition),
147 Struct(StructDefinition),
149 Enum(EnumDefinition),
151 Type(TypeDefinition),
153}
154
155impl ParseSource {
156 pub fn ident(&self) -> String {
158 match self {
159 Self::Contract(contract) => contract.name.safe_unwrap().name.to_owned(),
160 Self::Variable(var) => var.name.safe_unwrap().name.to_owned(),
161 Self::Event(event) => event.name.safe_unwrap().name.to_owned(),
162 Self::Error(error) => error.name.safe_unwrap().name.to_owned(),
163 Self::Struct(structure) => structure.name.safe_unwrap().name.to_owned(),
164 Self::Enum(enumerable) => enumerable.name.safe_unwrap().name.to_owned(),
165 Self::Function(func) => {
166 func.name.as_ref().map_or(func.ty.to_string(), |n| n.name.to_owned())
167 }
168 Self::Type(ty) => ty.name.name.to_owned(),
169 }
170 }
171
172 pub fn signature(&self) -> String {
174 match self {
175 Self::Function(func) => function_signature(func),
176 _ => self.ident(),
177 }
178 }
179
180 pub fn range(&self) -> Range<usize> {
182 match self {
183 Self::Contract(contract) => contract.loc,
184 Self::Variable(var) => var.loc,
185 Self::Event(event) => event.loc,
186 Self::Error(error) => error.loc,
187 Self::Struct(structure) => structure.loc,
188 Self::Enum(enumerable) => enumerable.loc,
189 Self::Function(func) => func.loc_prototype,
190 Self::Type(ty) => ty.loc,
191 }
192 .range()
193 }
194}