1use crate::handle::Handle;
9use crate::naming;
10use crate::parser::position::Position;
11use crate::prop_recursion_check::PropRecursionCheck;
12use std::collections::HashMap;
13use std::fmt;
14use std::hash::{Hash, Hasher};
15
16#[derive(Debug, Clone)]
18pub struct Name {
19 name: String,
20 alias: Option<String>,
21 pub position: Position,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub enum SimpleType {
26 String,
27 Integer,
28 Float,
29 Boolean,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub enum ValueType {
34 Simple(SimpleType),
35 List(Box<ValueType>),
36 TypeArg(Name),
37 LeapType { name: Name, args: Vec<ValueType> },
38}
39
40#[derive(Debug)]
42pub struct Prop {
43 pub name: Name,
44 pub prop_type: ValueType,
45 pub position: Position,
46 pub is_recursive: bool,
47}
48
49#[derive(Debug)]
50pub struct LeapStruct {
51 pub name: Name,
52 pub args: Vec<Name>,
53 pub props: Vec<Prop>,
54 pub path: String,
55 pub position: Position,
56}
57
58#[derive(Debug)]
59pub struct LeapEnum {
60 pub name: Name,
61 pub args: Vec<Name>,
62 pub variants: Vec<Prop>,
63 pub path: String,
64 pub position: Position,
65}
66
67#[derive(Debug)]
68pub enum LeapType {
69 Struct(LeapStruct),
70 Enum(LeapEnum),
71}
72
73pub type LeapTypeHandle = Handle<LeapType>;
74
75#[derive(Debug)]
76pub struct LeapSpec {
77 types: Vec<LeapType>,
78 name_to_type: HashMap<String, LeapTypeHandle>,
79}
80
81#[derive(Debug)]
82pub struct Comment {
83 pub comment: String,
84 pub comment_type: CommentType,
85 pub position: Position,
86}
87
88#[derive(Debug, Clone, Copy, PartialEq)]
89pub enum CommentType {
90 Line,
92 Separator,
94 Trail,
96}
97
98fn aliased_from_aliases(name: &Name, aliases: &HashMap<String, String>) -> Result<Name, String> {
99 name.to_aliased_if_some(aliases.get(name.get()).cloned())
100}
101
102impl Name {
103 pub fn new(name: String, position: Position) -> Result<Self, String> {
105 Ok(Name {
111 name,
112 alias: None,
113 position,
114 })
115 }
116
117 pub fn to_aliased(&self, alias: String) -> Result<Self, String> {
118 Ok(Name {
121 alias: Some(alias),
122 ..self.clone()
123 })
124 }
125
126 pub fn to_aliased_if_some(&self, alias: Option<String>) -> Result<Self, String> {
127 if let Some(a) = alias {
128 self.to_aliased(a)
129 } else {
130 Ok(Self::new(self.name.clone(), self.position)?)
131 }
132 }
133
134 pub fn get(&self) -> &str {
135 &self.name
136 }
137
138 fn get_aliased(&self) -> &str {
139 if let Some(alias) = &self.alias {
140 alias
141 } else {
142 &self.name
143 }
144 }
145
146 pub fn apply_style(&self, style: naming::WritingStyle, separator: &str) -> String {
147 naming::apply_style(style, separator, &naming::get_parts(self.get_aliased()))
148 }
149}
150
151impl fmt::Display for Name {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 write!(f, "{}", self.name)
154 }
155}
156
157impl PartialEq for Name {
158 fn eq(&self, other: &Self) -> bool {
159 self.name == other.name
160 }
161}
162
163impl Eq for Name {}
164
165impl Ord for Name {
166 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
167 self.name.cmp(&other.name)
168 }
169}
170
171impl PartialOrd for Name {
172 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
173 Some(self.cmp(other))
174 }
175}
176
177impl Hash for Name {
178 fn hash<H: Hasher>(&self, state: &mut H) {
179 self.name.hash(state);
180 }
181}
182
183impl SimpleType {
184 pub fn name(&self) -> String {
185 match self {
186 SimpleType::String => "str".to_owned(),
188 SimpleType::Integer => "int".to_owned(),
189 SimpleType::Float => "float".to_owned(),
190 SimpleType::Boolean => "bool".to_owned(),
191 }
192 }
193}
194
195impl fmt::Display for ValueType {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 match self {
198 Self::Simple(t) => match t {
199 SimpleType::String => write!(f, "str"),
200 SimpleType::Integer => write!(f, "int"),
201 SimpleType::Float => write!(f, "float"),
202 SimpleType::Boolean => write!(f, "bool"),
203 },
204 Self::List(t) => write!(f, "list[{}]", t),
205 Self::TypeArg(n) => write!(f, "{}?", n),
206 Self::LeapType { name, args } => {
207 if args.is_empty() {
208 write!(f, "{}", name)
209 } else {
210 let args = args
211 .iter()
212 .map(|a| format!("{}", a))
213 .collect::<Vec<_>>()
214 .join(" ");
215 write!(f, "{}[{}]", name, args)
216 }
217 }
218 }
219 }
220}
221
222impl ValueType {
223 pub fn to_aliased(&self, aliases: &HashMap<String, String>) -> Result<Self, String> {
224 match self {
225 Self::List(t) => Ok(Self::List(Box::new(t.to_aliased(aliases)?))),
226 Self::TypeArg(n) => Ok(Self::TypeArg(aliased_from_aliases(n, aliases)?)),
227 Self::LeapType { name, args } => Ok(Self::LeapType {
228 name: aliased_from_aliases(name, aliases)?,
229 args: args
230 .iter()
231 .map(|a| a.to_aliased(aliases))
232 .collect::<Result<_, _>>()?,
233 }),
234 _ => Ok(self.clone()),
235 }
236 }
237
238 pub fn name(&self) -> String {
239 match self {
240 Self::Simple(t) => t.name(),
241 Self::List(_) => "list".to_owned(),
242 Self::TypeArg(n) => n.get().to_owned(),
243 Self::LeapType { name, .. } => name.get().to_owned(),
244 }
245 }
246
247 pub fn args(&self) -> Vec<ValueType> {
248 match self {
249 Self::Simple(_) | Self::TypeArg(_) => vec![],
250 Self::List(t) => vec![t.as_ref().clone()],
251 Self::LeapType { args, .. } => args.clone(),
252 }
253 }
254
255 pub fn apply_args(&self, applied_args: &HashMap<&Name, &ValueType>) -> Self {
256 match self {
257 Self::Simple(_) => self.clone(),
258 Self::List(t) => Self::List(Box::new(t.apply_args(applied_args))),
259 Self::TypeArg(name) => (*applied_args.get(name).unwrap()).clone(),
260 Self::LeapType { name, args } => Self::LeapType {
261 name: name.clone(),
262 args: args.iter().map(|a| a.apply_args(applied_args)).collect(),
263 },
264 }
265 }
266}
267
268impl fmt::Display for Prop {
269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270 write!(f, "{}: {}", self.name, self.prop_type)
271 }
272}
273
274impl Prop {
275 pub fn to_aliased(&self, aliases: &HashMap<String, String>) -> Result<Self, String> {
276 Ok(Self {
277 name: aliased_from_aliases(&self.name, aliases)?,
278 prop_type: self.prop_type.to_aliased(aliases)?,
279 position: self.position,
280 is_recursive: self.is_recursive,
281 })
282 }
283
284 pub fn apply_args(&self, applied_args: &HashMap<&Name, &ValueType>) -> Self {
285 Self {
286 name: self.name.clone(),
287 prop_type: self.prop_type.apply_args(applied_args),
288 position: self.position,
289 is_recursive: self.is_recursive,
290 }
291 }
292}
293
294impl fmt::Display for LeapStruct {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 let args = self
297 .args
298 .iter()
299 .map(|a| a.get())
300 .collect::<Vec<_>>()
301 .join(" ");
302 let props = self
303 .props
304 .iter()
305 .map(|p| format!("{}", p))
306 .collect::<Vec<_>>()
307 .join(", ");
308 write!(
309 f,
310 "Struct({} args: [{}], props: [{}])",
311 self.name, args, props
312 )
313 }
314}
315
316impl LeapStruct {
317 pub fn to_aliased(&self, aliases: &HashMap<String, String>) -> Result<Self, String> {
318 Ok(Self {
319 name: aliased_from_aliases(&self.name, aliases)?,
320 args: self
321 .args
322 .iter()
323 .map(|a| aliased_from_aliases(a, aliases))
324 .collect::<Result<_, _>>()?,
325 props: self
326 .props
327 .iter()
328 .map(|p| p.to_aliased(aliases))
329 .collect::<Result<_, _>>()?,
330 path: self.path.clone(),
331 position: self.position,
332 })
333 }
334
335 pub fn map_args<'a>(&'a self, applied_args: &'a [ValueType]) -> HashMap<&Name, &ValueType> {
336 let mut args_map = HashMap::new();
337 for (i, name) in self.args.iter().enumerate() {
338 args_map.insert(name, &applied_args[i]);
340 }
341 args_map
342 }
343
344 pub fn apply_args(&self, applied_args: &HashMap<&Name, &ValueType>) -> Self {
345 Self {
346 name: self.name.clone(),
347 args: vec![],
349 props: self
350 .props
351 .iter()
352 .map(|p| p.apply_args(applied_args))
353 .collect(),
354 path: self.path.clone(),
355 position: self.position,
356 }
357 }
358
359 pub fn expand_args(&self, applied_args: &HashMap<&Name, &ValueType>) -> Vec<ValueType> {
360 self.args
361 .iter()
362 .map(|a| (*applied_args.get(a).unwrap()).clone())
363 .collect()
364 }
365}
366
367impl fmt::Display for LeapEnum {
368 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369 let args = self
370 .args
371 .iter()
372 .map(|a| a.get())
373 .collect::<Vec<_>>()
374 .join(" ");
375 let variants = self
376 .variants
377 .iter()
378 .map(|v| format!("{}", v))
379 .collect::<Vec<_>>()
380 .join(", ");
381 write!(
382 f,
383 "Enum({} args: [{}], variants: [{}])",
384 self.name, args, variants
385 )
386 }
387}
388
389impl LeapEnum {
390 pub fn to_aliased(&self, aliases: &HashMap<String, String>) -> Result<Self, String> {
391 Ok(Self {
392 name: aliased_from_aliases(&self.name, aliases)?,
393 args: self
394 .args
395 .iter()
396 .map(|a| aliased_from_aliases(a, aliases))
397 .collect::<Result<_, _>>()?,
398 variants: self
399 .variants
400 .iter()
401 .map(|v| v.to_aliased(aliases))
402 .collect::<Result<_, _>>()?,
403 path: self.path.clone(),
404 position: self.position,
405 })
406 }
407
408 pub fn expand_args(&self, applied_args: &HashMap<&Name, &ValueType>) -> Vec<ValueType> {
409 self.args
410 .iter()
411 .map(|a| (*applied_args.get(a).unwrap()).clone())
412 .collect()
413 }
414
415 pub fn map_args<'a>(&'a self, applied_args: &'a [ValueType]) -> HashMap<&Name, &ValueType> {
416 let mut args_map = HashMap::new();
417 for (i, name) in self.args.iter().enumerate() {
418 args_map.insert(name, &applied_args[i]);
420 }
421 args_map
422 }
423
424 pub fn apply_args(&self, applied_args: &HashMap<&Name, &ValueType>) -> Self {
425 Self {
426 name: self.name.clone(),
427 args: vec![],
429 variants: self
430 .variants
431 .iter()
432 .map(|v| v.apply_args(applied_args))
433 .collect(),
434 path: self.path.clone(),
435 position: self.position,
436 }
437 }
438}
439
440impl fmt::Display for LeapType {
441 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442 match self {
443 Self::Struct(t) => write!(f, "Type({})", t),
444 Self::Enum(e) => write!(f, "Type({})", e),
445 }
446 }
447}
448
449impl LeapType {
450 pub fn as_struct(&self) -> Option<&LeapStruct> {
451 if let LeapType::Struct(s) = self {
452 Some(s)
453 } else {
454 None
455 }
456 }
457
458 pub fn as_enum(&self) -> Option<&LeapEnum> {
459 if let LeapType::Enum(e) = self {
460 Some(e)
461 } else {
462 None
463 }
464 }
465
466 pub fn is_struct(&self) -> bool {
467 matches!(self, LeapType::Struct(_))
468 }
469
470 pub fn is_enum(&self) -> bool {
471 matches!(self, LeapType::Enum(_))
472 }
473
474 pub fn to_aliased(&self, aliases: &HashMap<String, String>) -> Result<Self, String> {
475 Ok(match self {
476 Self::Struct(s) => Self::Struct(s.to_aliased(aliases)?),
477 Self::Enum(e) => Self::Enum(e.to_aliased(aliases)?),
478 })
479 }
480
481 pub fn name(&self) -> &Name {
482 match self {
483 Self::Enum(e) => &e.name,
484 Self::Struct(s) => &s.name,
485 }
486 }
487
488 pub fn args(&self) -> &[Name] {
489 match self {
490 Self::Enum(e) => &e.args,
491 Self::Struct(s) => &s.args,
492 }
493 }
494
495 pub fn path(&self) -> &str {
496 match self {
497 Self::Enum(e) => &e.path,
498 Self::Struct(s) => &s.path,
499 }
500 }
501
502 pub fn set_path(&mut self, path: String) {
503 match self {
504 Self::Enum(e) => e.path = path,
505 Self::Struct(s) => s.path = path,
506 }
507 }
508
509 pub fn position(&self) -> &Position {
510 match self {
511 Self::Enum(e) => &e.position,
512 Self::Struct(s) => &s.position,
513 }
514 }
515
516 pub fn expand_args(&self, applied_args: &HashMap<&Name, &ValueType>) -> Vec<ValueType> {
517 match self {
518 Self::Enum(e) => e.expand_args(applied_args),
519 Self::Struct(s) => s.expand_args(applied_args),
520 }
521 }
522
523 pub fn apply_args(&self, args: &[ValueType]) -> Self {
524 match self {
525 LeapType::Struct(s) => LeapType::Struct(s.apply_args(&s.map_args(args))),
526 LeapType::Enum(e) => LeapType::Enum(e.apply_args(&e.map_args(args))),
527 }
528 }
529}
530
531impl fmt::Display for LeapSpec {
532 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533 write!(
534 f,
535 "Spec({})",
536 self.types
537 .iter()
538 .map(|t| format!("{}", t))
539 .collect::<Vec<_>>()
540 .join(", ")
541 )
542 }
543}
544
545impl IntoIterator for LeapSpec {
546 type Item = LeapType;
547 type IntoIter = std::vec::IntoIter<Self::Item>;
548
549 fn into_iter(self) -> Self::IntoIter {
550 self.types.into_iter()
551 }
552}
553
554impl LeapSpec {
555 pub fn new(types: Vec<LeapType>) -> Self {
556 let mut spec = Self {
557 types: vec![],
558 name_to_type: HashMap::new(),
559 };
560 for leap_type in types.into_iter() {
561 spec.push_type(leap_type);
562 }
563 spec
564 }
565
566 fn push_type(&mut self, leap_type: LeapType) {
567 let name = leap_type.name().get().to_owned();
568 self.types.push(leap_type);
569 self.name_to_type
570 .insert(name, LeapTypeHandle::new((self.types.len() - 1) as u32));
571 }
572
573 pub fn iter_type_refs(&self) -> impl Iterator<Item = &LeapType> {
574 self.types.iter()
575 }
576
577 pub fn iter_types(&self) -> impl Iterator<Item = LeapTypeHandle> {
578 (0..self.types.len()).map(|i| LeapTypeHandle::new(i as u32))
579 }
580
581 pub fn join(&mut self, other: LeapSpec) {
582 for leap_type in other.into_iter() {
584 self.push_type(leap_type);
585 }
586 }
587
588 pub fn get_type_ref(&self, handle: LeapTypeHandle) -> &LeapType {
589 &self.types[handle.as_index()]
590 }
591
592 pub fn get_type_mut(&mut self, handle: LeapTypeHandle) -> &mut LeapType {
593 &mut self.types[handle.as_index()]
594 }
595
596 pub fn get_handle_by_name(&self, name: &str) -> Option<LeapTypeHandle> {
597 self.name_to_type.get(name).copied()
598 }
599
600 pub fn get_type_by_name(&self, name: &str) -> Option<&LeapType> {
601 self.get_handle_by_name(name).map(|h| self.get_type_ref(h))
602 }
603
604 pub fn is_struct_name(&self, name: &str) -> bool {
605 if let Some(t) = self.get_type_by_name(name) {
606 t.is_struct()
607 } else {
608 false
609 }
610 }
611
612 pub fn is_enum_name(&self, name: &str) -> bool {
613 if let Some(t) = self.get_type_by_name(name) {
614 t.is_enum()
615 } else {
616 false
617 }
618 }
619
620 pub fn to_aliased(&self, aliases: &HashMap<String, String>) -> Result<Self, String> {
621 Ok(Self::new(
622 self.types
623 .iter()
624 .map(|t| t.to_aliased(aliases))
625 .collect::<Result<_, _>>()?,
626 ))
627 }
628
629 pub fn mark_recursive_props(&mut self) {
630 for h in self.iter_types() {
631 let mut recursive_props = vec![];
632 let t = self.get_type_ref(h);
633 match t {
634 LeapType::Struct(s) => {
635 for (i, p) in s.props.iter().enumerate() {
636 if PropRecursionCheck::is_recursive(self, t, p) {
637 recursive_props.push(i);
638 }
639 }
640 }
641 LeapType::Enum(e) => {
642 for (i, v) in e.variants.iter().enumerate() {
643 if PropRecursionCheck::is_recursive(self, t, v) {
644 recursive_props.push(i);
645 }
646 }
647 }
648 }
649 if !recursive_props.is_empty() {
650 let props = match self.get_type_mut(h) {
651 LeapType::Struct(s) => &mut s.props,
652 LeapType::Enum(e) => &mut e.variants,
653 };
654 for i in recursive_props {
655 props[i].is_recursive = true;
656 }
657 }
658 }
659 }
660}
661
662#[cfg(test)]
663mod test {
664 use crate::parser::parser::Parser;
665
666 use super::*;
667
668 #[test]
669 fn test_simple() {
670 let spec_text = "
671 .struct s1
672 a: s2
673 b: s3
674
675 .struct s2
676 a: s1
677
678 .struct s3
679 a: str
680 ";
681 let mut spec = LeapSpec::new(Parser::parse(spec_text).unwrap());
682 spec.mark_recursive_props();
683 let s = spec.get_type_by_name("s1").unwrap().as_struct().unwrap();
684 assert!(s.props[0].is_recursive);
685 assert!(!s.props[1].is_recursive);
686 }
687}