34
35:- module(prolog_format,
36 [ format_spec/2, 37 format_spec//1, 38 format_types/2 39 ]). 40:- autoload(library(error),[is_of_type/2,existence_error/2]). 41:- autoload(library(when),[when/2]). 42:- autoload(library(dcg/basics),[eos//0,string_without//2,integer//1]).
74format_spec(Format, Spec) :-
75 when((ground(Format);ground(Codes)),text_codes(Format, Codes)),
76 once(phrase(format_spec(Spec), Codes, [])).
83format_spec([]) -->
84 eos.
85format_spec([escape(Numeric,Modifier,Action)|Rest]) -->
86 "~",
87 numeric_argument(Numeric),
88 modifier_argument(Modifier),
89 action(Action),
90 format_spec(Rest).
91format_spec([text(String)|Rest]) -->
92 { when((ground(String);ground(Codes)),string_codes(String, Codes)) },
93 string_without("~", Codes),
94 { Codes \= [] },
95 format_spec(Rest).
104format_types(Format, Types) :-
105 format_spec(Format, Spec),
106 spec_types(Spec, Types).
114spec_types(Spec, Types) :-
115 phrase(spec_types(Spec), Types).
116
117spec_types([]) -->
118 [].
119spec_types([Item|Items]) -->
120 item_types(Item),
121 spec_types(Items).
122
123item_types(text(_)) -->
124 [].
125item_types(escape(Numeric,_,Action)) -->
126 numeric_types(Numeric),
127 action_types(Action).
128
129numeric_types(number(_)) -->
130 [].
131numeric_types(character(_)) -->
132 [].
133numeric_types(star) -->
134 [number].
135numeric_types(nothing) -->
136 [].
137
138action_types(Action) -->
139 { atom_codes(Action, [Code]) },
140 { action_types(Code, Types) },
141 phrase(Types).
144text_codes(Var, Codes) :-
145 var(Var),
146 !,
147 string_codes(Var, Codes).
148text_codes(Atom, Codes) :-
149 atom(Atom),
150 !,
151 atom_codes(Atom, Codes).
152text_codes(String, Codes) :-
153 string(String),
154 !,
155 string_codes(String, Codes).
156text_codes(Codes, Codes) :-
157 is_of_type(codes, Codes).
158
159
160numeric_argument(number(N)) -->
161 integer(N).
162numeric_argument(character(C)) -->
163 "`",
164 [C].
165numeric_argument(star) -->
166 "*".
167numeric_argument(nothing) -->
168 "".
169
170modifier_argument(colon) -->
171 ":".
172modifier_argument(no_colon) -->
173 \+ ":".
174
175action(Char) -->
176 [C],
177 { char_code(Char, C),
178 ( is_action(C)
179 -> true
180 ; existence_error(format_character, Char)
181 )
182 }.
190is_action(Action) :-
191 action_types(Action, _).
203action_types(0'~, []).
204action_types(0'a, [atom]).
205action_types(0'c, [integer]). 206action_types(0'd, [integer]).
207action_types(0'D, [integer]).
208action_types(0'e, [float]).
209action_types(0'E, [float]).
210action_types(0'f, [float]).
211action_types(0'g, [float]).
212action_types(0'G, [float]).
213action_types(0'i, [any]).
214action_types(0'I, [integer]).
215action_types(0'k, [any]).
216action_types(0'n, []).
217action_types(0'N, []).
218action_types(0'p, [any]).
219action_types(0'q, [any]).
220action_types(0'r, [integer]).
221action_types(0'R, [integer]).
222action_types(0's, [text]).
223action_types(0'@, [callable]).
224action_types(0't, []).
225action_types(0'|, []).
226action_types(0'+, []).
227action_types(0'w, [any]).
228action_types(0'W, [any, list])
Analyse format specifications
This library parses the format specification used by format/1, format/2 and format/3. The parsed specification can be used to validate the consistency of the format string and the provided arguments. For example: