1 (* Title: Isar/source.ML |
1 (* Title: Isar/source.ML |
2 ID: $Id$ |
2 ID: $Id$ |
3 Author: Markus Wenzel, TU Muenchen |
3 Author: Markus Wenzel, TU Muenchen |
4 |
4 |
5 Co-algebraic data sources. |
5 Co-algebraic data sources. |
6 |
|
7 TODO: |
|
8 - proper handling of interrupts (?); |
|
9 - recovery from scan errors (?); |
|
10 - make prompt part of source (?); |
|
11 *) |
6 *) |
12 |
7 |
13 signature SOURCE = |
8 signature SOURCE = |
14 sig |
9 sig |
15 type ('a, 'b) source |
10 type ('a, 'b) source |
16 val get: string -> ('a, 'b) source -> 'a list * ('a, 'b) source |
11 val set_prompt: string -> ('a, 'b) source -> ('a, 'b) source |
|
12 val get: ('a, 'b) source -> 'a list * ('a, 'b) source |
17 val unget: 'a list * ('a, 'b) source -> ('a, 'b) source |
13 val unget: 'a list * ('a, 'b) source -> ('a, 'b) source |
18 val get_single: string -> ('a, 'b) source -> 'a * ('a, 'b) source |
14 val get_single: ('a, 'b) source -> 'a * ('a, 'b) source |
19 val exhaust: string -> ('a, 'b) source -> 'a list |
15 val exhaust: ('a, 'b) source -> 'a list |
20 val filter: ('a -> bool) -> ('a, 'b) source -> ('a, ('a, 'b) source) source |
16 val filter: ('a -> bool) -> ('a, 'b) source -> ('a, ('a, 'b) source) source |
21 val of_list: int option -> 'a list -> ('a, 'a list) source |
17 val of_list: 'a list -> ('a, 'a list) source |
22 val of_string: int option -> string -> (string, string list) source |
18 val of_string: string -> (string, string list) source |
23 val of_stream: TextIO.instream -> TextIO.outstream -> (string, unit) source |
19 val of_stream: TextIO.instream -> TextIO.outstream -> (string, unit) source |
24 val tty: (string, unit) source |
20 val tty: (string, unit) source |
25 val state_source: 'a -> 'b * ('b -> bool) -> ('a * 'b list -> 'c list * ('a * 'b list)) |
21 val state_source: 'a -> 'b * ('b -> bool) -> ('a * 'b list -> 'c list * ('a * 'b list)) |
26 -> ('b, 'd) source -> ('c, 'a * ('b, 'd) source) source |
22 -> ('b, 'd) source -> ('c, 'a * ('b, 'd) source) source |
27 val source: 'a * ('a -> bool) -> ('a list -> 'b list * 'a list) |
23 val source: 'a * ('a -> bool) -> ('a list -> 'b list * 'a list) |
37 |
33 |
38 datatype ('a, 'b) source = |
34 datatype ('a, 'b) source = |
39 Source of |
35 Source of |
40 {buffer: 'a list, |
36 {buffer: 'a list, |
41 info: 'b, |
37 info: 'b, |
|
38 prompt: string option, |
42 drain: string -> 'b -> 'a list * 'b}; |
39 drain: string -> 'b -> 'a list * 'b}; |
43 |
40 |
44 fun make_source buffer info drain = |
41 fun make_source buffer info prompt drain = |
45 Source {buffer = buffer, info = info, drain = drain}; |
42 Source {buffer = buffer, info = info, prompt = prompt, drain = drain}; |
|
43 |
|
44 |
|
45 (* prompt *) |
|
46 |
|
47 val default_prompt = "> "; |
|
48 |
|
49 fun set_prompt prompt (Source {buffer, info, prompt = _, drain}) = |
|
50 make_source buffer info (Some prompt) drain; |
46 |
51 |
47 |
52 |
48 (* get / unget *) |
53 (* get / unget *) |
49 |
54 |
50 fun get prompt (Source {buffer = [], info, drain}) = |
55 fun get (Source {buffer = [], info, prompt, drain}) = |
51 let val (xs, info') = drain prompt info |
56 let val (xs, info') = drain (if_none prompt default_prompt) info |
52 in (xs, make_source [] info' drain) end |
57 in (xs, make_source [] info' prompt drain) end |
53 | get _ (Source {buffer, info, drain}) = |
58 | get (Source {buffer, info, prompt, drain}) = |
54 (buffer, make_source [] info drain); |
59 (buffer, make_source [] info prompt drain); |
55 |
60 |
56 fun unget (xs, Source {buffer, info, drain}) = |
61 fun unget (xs, Source {buffer, info, prompt, drain}) = |
57 make_source (xs @ buffer) info drain; |
62 make_source (xs @ buffer) info prompt drain; |
58 |
63 |
59 |
64 |
60 fun get_single prompt src = |
65 (* variations on get *) |
61 (case get prompt src of |
66 |
|
67 fun get_prompt prompt src = get (set_prompt prompt src); |
|
68 |
|
69 fun get_single src = |
|
70 (case get src of |
62 ([], _) => error "Input source exhausted!" |
71 ([], _) => error "Input source exhausted!" |
63 | (x :: xs, src') => (x, unget (xs, src'))); |
72 | (x :: xs, src') => (x, unget (xs, src'))); |
64 |
73 |
65 fun exhaust prompt src = |
74 fun exhaust src = |
66 (case get prompt src of |
75 (case get src of |
67 ([], _) => [] |
76 ([], _) => [] |
68 | (xs, src') => xs @ exhaust prompt src'); |
77 | (xs, src') => xs @ exhaust src'); |
69 |
78 |
70 |
79 |
71 (* filter *) |
80 (* filter *) |
72 |
81 |
73 fun drain_filter pred prompt src = |
82 fun drain_filter pred prompt src = |
74 let |
83 let |
75 val (xs, src') = get prompt src; |
84 val (xs, src') = get src; |
76 val xs' = Library.filter pred xs; |
85 val xs' = Library.filter pred xs; |
77 in |
86 in |
78 if null xs then (xs, src') |
87 if null xs then (xs, src') |
79 else if null xs' then drain_filter pred prompt src' |
88 else if null xs' then drain_filter pred prompt src' |
80 else (xs', src') |
89 else (xs', src') |
81 end; |
90 end; |
82 |
91 |
83 fun filter pred src = make_source [] src (drain_filter pred); |
92 fun filter pred src = make_source [] src None (drain_filter pred); |
84 |
93 |
85 |
94 |
86 |
95 |
87 (** build sources **) |
96 (** build sources **) |
88 |
97 |
89 (* list source *) |
98 (* list source *) |
90 |
99 |
91 fun drain_list _ xs = (xs, []); |
100 (*limiting the master input buffer considerably improves performance*) |
92 fun drain_list_limit n _ xs = (take (n, xs), drop (n, xs)); |
101 val limit = 4000; |
93 |
102 |
94 fun of_list None xs = make_source [] xs drain_list |
103 fun drain_list _ xs = (take (limit, xs), drop (limit, xs)); |
95 | of_list (Some n) xs = make_source [] xs (drain_list_limit (Int.max (n, 1))); |
|
96 |
104 |
97 fun of_string limit str = of_list limit (explode str); |
105 fun of_list xs = make_source [] xs None drain_list; |
|
106 fun of_string str = of_list (explode str); |
98 |
107 |
99 |
108 |
100 (* stream source *) |
109 (* stream source *) |
101 |
110 |
102 fun drain_stream instream outstream prompt () = |
111 fun drain_stream instream outstream prompt () = |
103 (TextIO.output (outstream, prompt); |
112 (TextIO.output (outstream, prompt); |
104 TextIO.flushOut outstream; |
113 TextIO.flushOut outstream; |
105 (explode (TextIO.inputLine instream), ())); |
114 (explode (TextIO.inputLine instream), ())); |
106 |
115 |
107 fun of_stream instream outstream = |
116 fun of_stream instream outstream = |
108 make_source [] () (drain_stream instream outstream); |
117 make_source [] () None (drain_stream instream outstream); |
109 |
118 |
110 val tty = of_stream TextIO.stdIn TextIO.stdOut; |
119 val tty = of_stream TextIO.stdIn TextIO.stdOut; |
111 |
120 |
112 |
121 |
113 |
122 |
114 (** compose sources **) |
123 (** compose sources **) |
115 |
124 |
116 (* make state-based *) |
125 (* make state-based *) |
117 |
126 |
118 fun drain_state_source stopper scan prompt state_src = |
127 fun drain_state_source stopper scan prompt state_src = |
119 Scan.source prompt get unget stopper scan state_src; |
128 Scan.source prompt get_prompt unget stopper scan state_src; |
120 |
129 |
121 fun state_source init_state stopper scan src = |
130 fun state_source init_state stopper scan src = |
122 make_source [] (init_state, src) (drain_state_source stopper scan); |
131 make_source [] (init_state, src) None (drain_state_source stopper scan); |
123 |
132 |
124 |
133 |
125 (* not state-based *) |
134 (* not state-based *) |
126 |
135 |
127 fun drain_source stopper scan prompt src = |
136 fun drain_source stopper scan prompt src = |
128 apsnd snd (Scan.source prompt get unget stopper (Scan.lift scan) ((), src)); |
137 apsnd snd (Scan.source prompt get_prompt unget stopper (Scan.lift scan) ((), src)); |
129 |
138 |
130 fun source stopper scan src = |
139 fun source stopper scan src = |
131 make_source [] src (drain_source stopper scan); |
140 make_source [] src None (drain_source stopper scan); |
132 |
141 |
133 |
142 |
134 |
143 |
135 (** test source interactively **) |
144 (** test source interactively **) |
136 |
145 |
137 fun test str_of src = |
146 fun test str_of src = |
138 (case get ">> " src handle Interrupt => ([], src) of |
147 (case get src handle Interrupt => ([], src) of |
139 ([], _) => writeln "Terminated." |
148 ([], _) => writeln "Terminated." |
140 | (xs, src') => (seq writeln (map str_of xs); test str_of src')); |
149 | (xs, src') => (seq writeln (map str_of xs); test str_of src')); |
141 |
150 |
142 |
151 |
143 end; |
152 end; |