1use crate::error::RegistryError;
6use crate::expression::{CompiledExpression, ParameterTypeRegistry};
7use crate::handler::Handler;
8use crate::step_kind::StepKind;
9use crate::value::Value;
10use std::collections::HashMap;
11use std::rc::Rc;
12
13pub use crate::expression::ParseFn;
14
15pub type FormatFn = Rc<dyn Fn(&Value) -> Option<String>>;
19
20#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct CustomParameterType {
24 pub name: String,
25 pub regexp: String,
26}
27
28impl CustomParameterType {
29 pub fn new(name: impl Into<String>, regexp: impl Into<String>) -> CustomParameterType {
30 CustomParameterType {
31 name: name.into(),
32 regexp: regexp.into(),
33 }
34 }
35}
36
37#[derive(Clone)]
40pub struct StepRegistration {
41 pub expression: String,
42 pub expression_source_file: String,
43 pub expression_source_line: usize,
44 pub handler: Handler,
45 pub compiled: CompiledExpression,
46 pub kind: Option<StepKind>,
47}
48
49#[derive(Clone)]
51pub struct Registry {
52 pub steps: Vec<Rc<StepRegistration>>,
53 pub parameter_types: ParameterTypeRegistry,
54 pub custom_parameter_types: Vec<CustomParameterType>,
55 pub formats: HashMap<String, FormatFn>,
56}
57
58pub fn create_registry() -> Registry {
63 let mut formats: HashMap<String, FormatFn> = HashMap::new();
64 formats.insert(
65 "emph".to_string(),
66 Rc::new(|v: &Value| match v {
67 Value::String(s) => Some(format!("*{s}*")),
68 _ => None,
69 }),
70 );
71 Registry {
72 steps: Vec::new(),
73 parameter_types: ParameterTypeRegistry::new(),
74 custom_parameter_types: Vec::new(),
75 formats,
76 }
77}
78
79pub fn add_step(
83 registry: &Registry,
84 expression: &str,
85 expression_source_file: &str,
86 expression_source_line: usize,
87 handler: Handler,
88 kind: Option<StepKind>,
89) -> Result<Registry, RegistryError> {
90 for existing in ®istry.steps {
91 if existing.expression == expression {
92 return Err(RegistryError::DuplicateStep(format!(
93 "duplicate step definition for \"{}\" at {}:{} and {}:{}",
94 expression,
95 existing.expression_source_file,
96 existing.expression_source_line,
97 expression_source_file,
98 expression_source_line
99 )));
100 }
101 }
102 let compiled = CompiledExpression::compile(expression, ®istry.parameter_types)
103 .map_err(|e| RegistryError::Expression(e.message))?;
104 let mut steps = registry.steps.clone();
105 steps.push(Rc::new(StepRegistration {
106 expression: expression.to_string(),
107 expression_source_file: expression_source_file.to_string(),
108 expression_source_line,
109 handler,
110 compiled,
111 kind,
112 }));
113 Ok(Registry {
114 steps,
115 parameter_types: registry.parameter_types.clone(),
116 custom_parameter_types: registry.custom_parameter_types.clone(),
117 formats: registry.formats.clone(),
118 })
119}
120
121pub fn define_parameter_type(
123 registry: &Registry,
124 name: &str,
125 regexp: &str,
126 parse: ParseFn,
127) -> Registry {
128 let mut parameter_types = registry.parameter_types.clone();
129 parameter_types.define(name, regexp, parse);
130 let mut custom_parameter_types = registry.custom_parameter_types.clone();
131 custom_parameter_types.push(CustomParameterType::new(name, regexp));
132 Registry {
133 steps: registry.steps.clone(),
134 parameter_types,
135 custom_parameter_types,
136 formats: registry.formats.clone(),
137 }
138}
139
140pub fn define_parameter_type_with_format(
142 registry: &Registry,
143 name: &str,
144 regexp: &str,
145 parse: ParseFn,
146 format: FormatFn,
147) -> Registry {
148 let mut next = define_parameter_type(registry, name, regexp, parse);
149 next.formats.insert(name.to_string(), format);
150 next
151}