src/Pure/Syntax/source.ML
changeset 4946 d8e5c6e31854
parent 4939 33af5d3dae1f
child 4954 cf1404c3f7bb
equal deleted inserted replaced
4945:d8c809afafb8 4946:d8e5c6e31854
     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;