amethyst/
parser.rs

1// Call Haskell Parser through FFI
2// Construct the resulting syntax
3use std::ffi::{CStr, CString};
4use std::os::raw::c_char;
5
6use crate::syntax::*;
7
8extern "C" {
9    fn initialize_haskell();
10    fn exit_haskell();
11    fn amethyst_parser(code: *const c_char) -> *mut i32;
12    fn free_result(result_ptr: *mut i32);
13    // Move function
14    fn move_type(move_ptr: *mut i32) -> i32;
15    // Transition functions
16    fn transition_read_symbol(transition_ptr: *mut i32) -> c_char;
17    fn transition_write_symbol(transition_ptr: *mut i32) -> c_char;
18    fn transition_move_symbol(transition_ptr: *mut i32) -> *mut i32;
19    fn transition_new_state(transition_ptr: *mut i32) -> *mut c_char;
20    // State functions
21    fn state_type(state_ptr: *mut i32) -> i32;
22    fn state_name(state_ptr: *mut i32) -> *mut c_char;
23    fn state_is_initial(state_ptr: *mut i32) -> bool;
24    fn state_tr_len(state_ptr: *mut i32) -> i32;
25    fn state_transitions(state_ptr: *mut i32) -> *mut i32;
26    fn state_transition_i(transitions_ptr: *mut i32, i: i32) -> *mut i32;
27    // Macro functions
28    fn macro_type(macro_ptr: *mut i32) -> i32;
29    fn macro_string(macro_ptr: *mut i32) -> *mut c_char;
30    fn macro_number(macro_ptr: *mut i32) -> i32;
31    fn macro_move(macro_ptr: *mut i32) -> *mut i32;
32    fn macro_symbol(macro_ptr: *mut i32) -> c_char;
33    fn macro_list_len(macro_ptr: *mut i32) -> i32;
34    fn macro_list(macro_ptr: *mut i32) -> *mut i32;
35    fn macro_list_i(macro_ptr: *mut i32, i: i32) -> *mut c_char;
36    // Machine functions
37    fn machine_components_len(machine_ptr: *mut i32) -> i32;
38    fn machine_components(machine_ptr: *mut i32) -> *mut i32;
39    fn machine_components_i_first(components_ptr: *mut i32, i: i32) -> *mut c_char;
40    fn machine_components_i_second(components_ptr: *mut i32, i: i32) -> *mut c_char;
41    fn machine_states_len(machine_ptr: *mut i32) -> i32;
42    fn machine_states(machine_ptr: *mut i32) -> *mut i32;
43    fn machine_states_i(states: *mut i32, i: i32) -> *mut i32;
44    // automaton functions
45    fn automaton_type(automaton_ptr: *mut i32) -> i32;
46    fn automaton_name(automaton_ptr: *mut i32) -> *mut c_char;
47    fn automaton_machine(automaton_ptr: *mut i32) -> *mut i32;
48    fn automaton_macro(automaton_ptr: *mut i32) -> *mut i32;
49    // Result functions
50    fn result_type(result_ptr: *mut i32) -> i32;
51    fn result_program_len(program_ptr: *mut i32) -> i32;
52    fn program_automata(program_ptr: *mut i32) -> *mut i32;
53    fn program_automata_i(automata_ptr: *mut i32, i: i32) -> *mut i32;
54    fn error_string(error_ptr: *mut i32) -> *mut c_char;
55    fn error_line(error_ptr: *mut i32) -> i32;
56    fn error_column(error_ptr: *mut i32) -> i32;
57}
58
59fn parse_move(move_ptr: *mut i32) -> Move {
60    unsafe {
61        match move_type(move_ptr) {
62            0 => Move::Left,
63            1 => Move::Right,
64            2 => Move::Neutral,
65            _ => panic!("Unexpected move type"),
66        }
67    }
68}
69
70pub fn parse_transition(transition_ptr: *mut i32) -> Transition {
71    unsafe {
72        let read_symbol = transition_read_symbol(transition_ptr) as u8 as char;
73        let write_symbol = transition_write_symbol(transition_ptr) as u8 as char;
74        // Get the move as a pointer and then find which move it is
75        let move_ptr = transition_move_symbol(transition_ptr);
76        let move_symbol = parse_move(move_ptr);
77        // Convert from CString to Rust String
78        let new_state = CStr::from_ptr(transition_new_state(transition_ptr))
79            .to_str()
80            .expect("Error converting CString to String")
81            .to_owned();
82
83        Transition {
84            read_symbol,
85            write_symbol,
86            move_symbol,
87            new_state,
88        }
89    }
90}
91
92pub fn parse_state(state_ptr: *mut i32) -> StateType {
93    unsafe {
94        let state_name = CStr::from_ptr(state_name(state_ptr))
95            .to_str()
96            .expect("Error converting CString to String")
97            .to_owned();
98        match state_type(state_ptr) {
99            0 => StateType::Accept(state_name),
100            1 => StateType::Reject(state_name),
101            2 => {
102                let initial = state_is_initial(state_ptr);
103                let transitions_len = state_tr_len(state_ptr);
104                let transitions_ptr = state_transitions(state_ptr);
105                // Get transitions one by one
106                let transitions = Box::new(
107                    (0..transitions_len)
108                        .map(|i| state_transition_i(transitions_ptr, i))
109                        .map(parse_transition)
110                        .collect(),
111                );
112                StateType::State(
113                    state_name,
114                    State {
115                        initial,
116                        transitions,
117                    },
118                )
119            }
120            _ => panic!("Unexpected state type"),
121        }
122    }
123}
124
125pub fn parse_macro(macro_ptr: *mut i32) -> MacroType {
126    unsafe {
127        match macro_type(macro_ptr) {
128            0 => {
129                let macro_automaton = CStr::from_ptr(macro_string(macro_ptr))
130                    .to_str()
131                    .expect("Error converting CString to String")
132                    .to_owned();
133                MacroType::Complement(macro_automaton)
134            }
135            1 => {
136                let automaton_list_len = macro_list_len(macro_ptr);
137                let automaton_list_ptr = macro_list(macro_ptr);
138                // Get transitions one by one
139                let automaton_list = Box::new(
140                    (0..automaton_list_len)
141                        .map(|i| macro_list_i(automaton_list_ptr, i))
142                        .map(|s| {
143                            CStr::from_ptr(s)
144                                .to_str()
145                                .expect("Error converting CString to String")
146                                .to_owned()
147                        })
148                        .collect(),
149                );
150                MacroType::Intersect(automaton_list)
151            }
152            2 => {
153                let automaton_list_len = macro_list_len(macro_ptr);
154                let automaton_list_ptr = macro_list(macro_ptr);
155                // Get transitions one by one
156                let automaton_list = Box::new(
157                    (0..automaton_list_len)
158                        .map(|i| macro_list_i(automaton_list_ptr, i))
159                        .map(|s| {
160                            CStr::from_ptr(s)
161                                .to_str()
162                                .expect("Error converting CString to String")
163                                .to_owned()
164                        })
165                        .collect(),
166                );
167                MacroType::Reunion(automaton_list)
168            }
169            3 => {
170                let automaton_list_len = macro_list_len(macro_ptr);
171                let automaton_list_ptr = macro_list(macro_ptr);
172                // Get transitions one by one
173                let automaton_list = Box::new(
174                    (0..automaton_list_len)
175                        .map(|i| macro_list_i(automaton_list_ptr, i))
176                        .map(|s| {
177                            CStr::from_ptr(s)
178                                .to_str()
179                                .expect("Error converting CString to String")
180                                .to_owned()
181                        })
182                        .collect(),
183                );
184                MacroType::Chain(automaton_list)
185            }
186            4 => {
187                let number = macro_number(macro_ptr);
188                let automaton = CStr::from_ptr(macro_string(macro_ptr))
189                    .to_str()
190                    .expect("Error converting CString to String")
191                    .to_owned();
192                MacroType::Repeat(number as u32, automaton)
193            }
194            5 => {
195                let number = macro_number(macro_ptr);
196                let move_symbol = parse_move(macro_move(macro_ptr));
197                MacroType::Move(move_symbol, number as u32)
198            }
199            6 => {
200                let number = macro_number(macro_ptr);
201                let move_symbol = parse_move(macro_move(macro_ptr));
202                let override_symbol = macro_symbol(macro_ptr) as u8 as char;
203                MacroType::Override(move_symbol, number as u32, override_symbol)
204            }
205            7 => {
206                let macro_text = CStr::from_ptr(macro_string(macro_ptr))
207                    .to_str()
208                    .expect("Error converting CString to String")
209                    .to_owned();
210                MacroType::Place(macro_text)
211            }
212            8 => {
213                let number = macro_number(macro_ptr);
214                let move_symbol = parse_move(macro_move(macro_ptr));
215                MacroType::Shift(move_symbol, number as u32)
216            }
217            _ => panic!("Unexpected macro keyword type!"),
218        }
219    }
220}
221
222pub fn parse_machine(machine_ptr: *mut i32) -> Machine {
223    unsafe {
224        let comp_len = machine_components_len(machine_ptr);
225        let comp_list = machine_components(machine_ptr);
226        let components = Box::new(
227            (0..comp_len)
228                .map(|i| {
229                    (
230                        machine_components_i_first(comp_list, i),
231                        machine_components_i_second(comp_list, i),
232                    )
233                })
234                .map(|(s1, s2)| {
235                    (
236                        CStr::from_ptr(s1)
237                            .to_str()
238                            .expect("Error converting CString to String")
239                            .to_owned(),
240                        CStr::from_ptr(s2)
241                            .to_str()
242                            .expect("Error converting CString to String")
243                            .to_owned(),
244                    )
245                })
246                .collect(),
247        );
248        let states_len = machine_states_len(machine_ptr);
249        let states_list = machine_states(machine_ptr);
250        let states = Box::new(
251            (0..states_len)
252                .map(|i| machine_states_i(states_list, i))
253                .map(parse_state)
254                .collect(),
255        );
256        Machine { components, states }
257    }
258}
259
260pub fn parse_automaton(automaton_ptr: *mut i32) -> AutomatonType {
261    unsafe {
262        let automaton_name = CStr::from_ptr(automaton_name(automaton_ptr))
263            .to_str()
264            .expect("Error converting CString to String")
265            .to_owned();
266        match automaton_type(automaton_ptr) {
267            0 => AutomatonType::Machine(
268                automaton_name,
269                parse_machine(automaton_machine(automaton_ptr)),
270            ),
271
272            1 => AutomatonType::Macro(automaton_name, parse_macro(automaton_macro(automaton_ptr))),
273            _ => panic!("Unexpected automaton type"),
274        }
275    }
276}
277
278fn parse_program(program_ptr: *mut i32) -> Program {
279    unsafe {
280        let automaton_len = result_program_len(program_ptr);
281        let automata_list = program_automata(program_ptr);
282        let automata = Box::new(
283            (0..automaton_len)
284                .map(|i| program_automata_i(automata_list, i))
285                .map(parse_automaton)
286                .collect::<Vec<AutomatonType>>(),
287        );
288        Program { automata }
289    }
290}
291
292fn parse_error(error_ptr: *mut i32) -> String {
293    unsafe {
294        let error_string = CStr::from_ptr(error_string(error_ptr))
295            .to_str()
296            .expect("Error converting CString to String")
297            .to_owned();
298        let line = error_line(error_ptr);
299        let column = error_column(error_ptr);
300        return format!("Error: {} at line {} column {}", error_string, line, column);
301    }
302}
303
304pub fn parse_result(result_ptr: *mut i32) -> Result<Program, String> {
305    unsafe {
306        match result_type(result_ptr) {
307            0 => Ok(parse_program(result_ptr)),
308            1 => Err(parse_error(result_ptr)),
309            _ => panic!("Unexpected result type"),
310        }
311    }
312}
313
314pub fn parse_code(code: String) -> Result<Program, String> {
315    let result;
316    unsafe {
317        initialize_haskell();
318
319        let code_c = CString::new(code).expect("CString::new failed");
320        let result_ptr = amethyst_parser(code_c.as_ptr());
321        result = parse_result(result_ptr);
322        free_result(result_ptr);
323
324        exit_haskell();
325    }
326    result
327}