|
1 | 1 | :- module(regex_parsing,
|
2 | 2 | [
|
| 3 | + parse_regex_strings/4, |
| 4 | + format_errors/3, |
| 5 | + format_error/3, |
3 | 6 | parse_regex_strings/4
|
4 | 7 | ]
|
5 | 8 | ).
|
6 | 9 |
|
7 | 10 | :- use_module(regex_ast).
|
8 | 11 |
|
9 |
| -%! print_errors(+Input:string, +Errors:list) is det. |
| 12 | +%! format_errors(+Output_Stream:stream, +Input:string, +Errors:list) is det. |
10 | 13 | %
|
11 | 14 | % This predicate prints out the error list in a nicely formated way
|
12 | 15 | %
|
| 16 | +% @arg Output_Stream Where to write the formatted errors |
13 | 17 | % @arg Input The original string being parsed.
|
14 | 18 | % @arg Errors The list of errors to print
|
15 |
| -print_errors(_, _, []). |
16 |
| -print_errors(Output_Stream, Input, Errors) :- |
17 |
| - maplist(print_error(Output_Stream, Input), Errors). |
| 19 | +format_errors(_, _, []). |
| 20 | +format_errors(Output_Stream, Input, Errors) :- |
| 21 | + maplist(format_error(Output_Stream, Input), Errors). |
18 | 22 |
|
19 | 23 | write_single_arrow(Output_Stream, 0) :-
|
20 | 24 | format(Output_Stream, '^~n', []), !.
|
|
23 | 27 | M is N - 1,
|
24 | 28 | write_single_arrow(Output_Stream, M).
|
25 | 29 |
|
26 |
| -%! print_errors(+Input:string, +Error:list) is det. |
| 30 | +%! format_error(+Ouput_Stream:stream, +Input:string, +Error:list) is det. |
27 | 31 | %
|
28 | 32 | % This predicate prints out the error in a nicely formated way
|
29 | 33 | %
|
| 34 | +% @arg Output_Stream Where to write the formatted error |
30 | 35 | % @arg Input The original string being parsed.
|
31 | 36 | % @arg Error The list of errors to print
|
32 | 37 | % TODO: We should probably propagate information about where regex came from
|
33 |
| -print_error(Output_Stream, Input, error(Message, some(Pos))) :- |
| 38 | +format_error(Output_Stream, Input, error(Message, some(Pos))) :- |
34 | 39 | format(Output_Stream, 'ERROR: ~s at ~d~n', [Message, Pos]),
|
35 | 40 | format(Output_Stream, '~w~n', [Input]),
|
36 | 41 | write_single_arrow(Output_Stream, Pos).
|
37 | 42 |
|
38 |
| -print_error(Output_Stream, _Input, error(Message)) :- |
| 43 | +format_error(Output_Stream, _Input, error(Message)) :- |
39 | 44 | format(Output_Stream, 'ERROR: ~s~n', [Message]).
|
40 | 45 |
|
41 |
| -% TODO: I think it should be format_error instead of print_error |
42 |
| - |
43 | 46 | %! process_regex_string
|
44 | 47 | %
|
45 | 48 | % This is used by parse_regex_strings to both transform the string into an AST,
|
46 | 49 | % and to handle formatting the errors.
|
47 | 50 | %
|
48 |
| -process_regex_string(_Output_Stream, Regex_String, (Asts, Error_Flag), ([Ast | Asts], Error_Flag)) :- |
49 |
| - regex_ast:string_ast(Regex_String, Ast, []), !. |
50 |
| - |
51 |
| -% TODO: we should collapse these so that we only call string_ast once |
52 |
| -process_regex_string(Output_Stream, Regex_String, (Asts, _), (Asts, true)) :- |
53 |
| - regex_ast:string_ast(Regex_String, _, Errors), |
54 |
| - print_errors(Output_Stream, Regex_String, Errors). |
| 51 | +process_regex_string(Output_Stream, Regex_String, (Asts, Error_Flag), ([Ast | Asts], New_Error_Flag)) :- |
| 52 | + regex_ast:string_ast(Regex_String, Ast, Errors), !, |
| 53 | + handle_parse_errors(Output_Stream, Regex_String, Errors, Error_Flag, New_Error_Flag). |
55 | 54 |
|
56 |
| -process_regex_string(Output_Stream, Regex_String, (Asts, _), (Asts, true)) :- |
| 55 | +% If regex_ast:string_ast fails, we should catch that here. |
| 56 | +% Note that we don't get an AST here |
| 57 | +process_regex_string(Output_Stream, Regex_String, (Asts, Error_Flag), (Asts, New_Error_Flag)) :- |
57 | 58 | Errors = [error("Could not parse string", some(0))],
|
58 |
| - print_errors(Output_Stream, Regex_String, Errors). |
| 59 | + handle_parse_errors(Output_Stream, Regex_String, Errors, Error_Flag, New_Error_Flag). |
| 60 | + |
| 61 | +% |
| 62 | +% Handling Errors means formatting them and keeping track of |
| 63 | +% whether we've seen any with a flag |
| 64 | +% |
| 65 | +handle_parse_errors(_Output_Stream, _Regex_String, [], Error_Flag, Error_Flag). |
59 | 66 |
|
| 67 | +handle_parse_errors(Output_Stream, Regex_String, Errors, _Error_Flag, true) :- |
| 68 | + format_errors(Output_Stream, Regex_String, Errors). |
60 | 69 |
|
| 70 | +% |
| 71 | +% Once we have a list of ASTS, |
| 72 | +% we need at least one |
| 73 | +% We need to cominbe them |
| 74 | +% |
61 | 75 | handle_asts(Output_Stream, [], _, _, true) :-
|
62 | 76 | writeln(Output_Stream, "ERROR: No strings were parsed successfully").
|
63 | 77 |
|
64 | 78 | handle_asts(_, Asts, Ast, Error_Flag, Error_Flag) :-
|
65 | 79 | regex_ast:combined_asts(Asts, Ast).
|
66 | 80 |
|
67 | 81 |
|
68 |
| -%! parse_regex_strings |
| 82 | +%! parse_regex_strings(+Output_Stream:stream, +Regex_Strings:list, -Ast, -Error_Found_Flag) is det. |
69 | 83 | %
|
70 |
| -% This is the highest level handle for parsing strings, it takes in a list of strings |
| 84 | +% This is the highest level handle for parsing strings. |
| 85 | +% It takes in a list of strings, |
71 | 86 | % transforms them all into one Ast (by OR'ing them together),
|
72 | 87 | % and formats the errors into an output_stream.
|
73 | 88 | %
|
| 89 | +% @arg Ouput_Stream Where to write any formatted errors |
| 90 | +% @arg Regex_Strings The strings to parse as regular expressions |
| 91 | +% @arg AST The resulting AST |
| 92 | +% @arg Error_Found_Flag Will be true if any errors were found |
74 | 93 | parse_regex_strings(
|
75 | 94 | Output_Stream,
|
76 | 95 | Regex_Strings,
|
|
113 | 132 | test_write_single_arrow(Num, Correct_Arrow)
|
114 | 133 | ).
|
115 | 134 |
|
116 |
| -test_print_error(Error, Correct_Output) :- |
| 135 | +test_format_error(Error, Correct_Output) :- |
117 | 136 | with_output_to(string(Arrow),
|
118 |
| - print_error(current_output, "aaaa", Error) |
| 137 | + format_error(current_output, "aaaa", Error) |
119 | 138 | ),
|
120 | 139 | assertion(Arrow = Correct_Output).
|
121 | 140 |
|
122 |
| -test(print_error) :- |
| 141 | +test(format_error) :- |
123 | 142 | Arrows = [
|
124 | 143 | (
|
125 | 144 | error("Wut", some(0)),
|
|
135 | 154 | )
|
136 | 155 | ],
|
137 | 156 | forall(member((Error, Correct_Output), Arrows),
|
138 |
| - test_print_error(Error, Correct_Output) |
| 157 | + test_format_error(Error, Correct_Output) |
139 | 158 | ).
|
140 | 159 |
|
141 | 160 | test_parse_regex_strings(Strings, Correct_Output, Correct_Ast, Correct_Error_Flag) :-
|
|
169 | 188 | (
|
170 | 189 | ["(a", "b"],
|
171 | 190 | "ERROR: No closing parenthesis at 0\n(a\n^\n",
|
172 |
| - ast_range(98, 98), |
| 191 | + ast_or(ast_range(97, 97), ast_range(98, 98)), |
173 | 192 | true
|
174 | 193 | ),
|
175 | 194 | (
|
|
0 commit comments