1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
pub( crate ) mod private
{
  use crate::
  {
    Program, Namespace,

    GrammarCommand, ExecutableCommand,

    Routine, wtools,
  };

  use former::Former;
  use std::collections::HashMap;
  use wtools::{ error::Result, err };

  /// This is the struct that provides a way to convert a `GrammarCommand` to an `ExecutableCommand`.
  ///
  /// The conversion is done by looking up the `Routine` associated with the command in a HashMap of routines.
  ///
  /// ```
  /// # use wca::{ Command, Type, GrammarCommand, ExecutorConverter, Routine };
  /// # use std::collections::HashMap;
  /// # fn main() -> Result< (), Box< dyn std::error::Error > > {
  /// let executor_converter = ExecutorConverter::former()
  /// .routine( "command", Routine::new( |( args, props )| Ok( () ) ) )
  /// .form();
  ///
  /// let grammar_command = GrammarCommand
  /// {
  ///   phrase : "command".to_string(),
  ///   subjects : vec![],
  ///   properties : HashMap::new(),
  /// };
  ///
  /// let executable_command = executor_converter.to_command( grammar_command )?;
  /// # Ok( () ) }
  /// ```
  #[ derive( Debug ) ]
  #[ derive( Former ) ]
  pub struct ExecutorConverter
  {
    pub( crate ) routines : HashMap< String, Routine >,
  }

  impl ExecutorConverterFormer
  {
    /// Inserts routine to a routine dictionary
    pub fn routine< S >( mut self, phrase : S, routine : Routine ) -> Self
    where
      S : Into< String >,
      Routine : Into< Routine >
    {
      let mut routines = self.routines.unwrap_or_default();

      routines.insert( phrase.into(), routine );

      self.routines = Some( routines );
      self
    }
  }

  impl ExecutorConverter
  {
    /// Converts raw program to executable
    pub fn to_program( &self, raw_program : Program< Namespace< GrammarCommand > > ) -> Result< Program< Namespace< ExecutableCommand > > >
    {
      let namespaces = raw_program.namespaces
      .into_iter()
      .map( | n | self.to_namespace( n ) )
      .collect::< Result< Vec< Namespace< ExecutableCommand > > > >()?;

      Ok( Program { namespaces } )
    }

    /// Converts raw namespace to executable
    pub fn to_namespace( &self, raw_namespace : Namespace< GrammarCommand > ) -> Result< Namespace< ExecutableCommand > >
    {
      let commands = raw_namespace.commands
      .into_iter()
      .map( | c | self.to_command( c ) )
      .collect::< Result< Vec< ExecutableCommand > > >()?;

      Ok( Namespace { commands } )
    }

    /// Converts raw command to executable
    pub fn to_command( &self, command : GrammarCommand ) -> Result< ExecutableCommand >
    {
      self.routines
      .get( &command.phrase )
      .ok_or_else( || err!( "Can not found routine for command `{}`", command.phrase ) )
      .map(
        | routine |
        ExecutableCommand
        {
          subjects : command.subjects,
          properties : command.properties,
          routine : routine.clone(),
        }
      )
    }
  }
}

//

crate::mod_interface!
{
  prelude use ExecutorConverter;
}