leap_lang/
leaptypes.rs

1// LeapType
2// LeapEnum
3// Name - StrongString - length, allowed symbols
4// todo: rename file to leapspec.rs? file per struct/enum?
5// todo: checks - enum variants should have unique names (eg. if need multiple variants of same type wrap in struct first)
6// todo: only allow structs to be variants of enum
7// todo: checks - type args should be unique relative to struct and enum names, same type arg names can be used in different types
8use 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// todo: trait Name to String
17#[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// todo: rename -> Property
41#[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    // comment takes full line
91    Line,
92    // empty line
93    Separator,
94    // comment follows some code on the same line
95    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    // todo: accept any name here? check names later, to simplify parsing (name can return error in parsing code)
104    pub fn new(name: String, position: Position) -> Result<Self, String> {
105        // todo: checks
106        // - min, max length?
107        // - allowed symbols? only control use of delimiter `-` (eg. can be only in the middle, no repeating)?
108        // - allowed start symbol?
109        // - allowed end symbol?
110        Ok(Name {
111            name,
112            alias: None,
113            position,
114        })
115    }
116
117    pub fn to_aliased(&self, alias: String) -> Result<Self, String> {
118        // todo: check alias for same `name` rules
119        // todo: when adding alias check there is no same name/alias, global type scoped, property names scoped, separate aliases for Types and for Props?
120        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            // todo: replace strings with constants
187            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            // applied_args should have same length as self.args
339            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            // as type args was applied there is no type args any more
348            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            // applied_args should have same length as self.args
419            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            // as type args was applied there is no type args any more
428            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        // todo: consume self, and return new spec? so new spec always created with `new`
583        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}