added catch: ('a -> 'b) -> 'a -> 'b;
authorwenzelm
Mon, 25 May 1998 21:12:46 +0200
changeset 4958 ad2acb8d2db4
parent 4957 30c49821e61f
child 4959 4ebdea556457
added catch: ('a -> 'b) -> 'a -> 'b; tuned source(');
src/Pure/Syntax/scan.ML
--- a/src/Pure/Syntax/scan.ML	Mon May 25 21:11:46 1998 +0200
+++ b/src/Pure/Syntax/scan.ML	Mon May 25 21:12:46 1998 +0200
@@ -46,13 +46,14 @@
   val finite': 'a * ('a -> bool) -> ('b * 'a list -> 'c * ('d * 'a list))
     -> 'b * 'a list -> 'c * ('d * 'a list)
   val finite: 'a * ('a -> bool) -> ('a list -> 'b * 'a list) -> 'a list -> 'b * 'a list
+  val catch: ('a -> 'b) -> 'a -> 'b
   val error: ('a -> 'b) -> 'a -> 'b
-  val source': string -> (string -> 'a -> 'b list * 'a) ->
-    ('b list * 'a -> 'c) -> 'b * ('b -> bool) -> ('d * 'b list -> 'e list * ('d * 'b list)) ->
-      'd * 'a -> 'e list * ('d * 'c)
-  val source: string -> (string -> 'a -> 'b list * 'a) ->
-    ('b list * 'a -> 'c) -> 'b * ('b -> bool) -> ('b list -> 'd list * 'b list) ->
-      'a -> 'd list * 'c
+  val source': string -> (string -> 'a -> 'b list * 'a) -> ('b list * 'a -> 'c) ->
+    'b * ('b -> bool) -> ('d * 'b list -> 'e list * ('d * 'b list)) ->
+    ('d * 'b list -> 'f * ('d * 'b list)) option -> 'd * 'a -> 'e list * ('d * 'c)
+  val source: string -> (string -> 'a -> 'b list * 'a) -> ('b list * 'a -> 'c) ->
+    'b * ('b -> bool) -> ('b list -> 'd list * 'b list) ->
+    ('b list -> 'e * 'b list) option -> 'a -> 'd list * 'c
   val single: ('a -> 'b * 'a) -> 'a -> 'b list * 'a
   val bulk: ('a -> 'b * 'a) -> 'a -> 'b list * 'a
   type lexicon
@@ -70,7 +71,7 @@
 
 (** scanners **)
 
-exception MORE of string option;	(*need more input (use prompt)*)
+exception MORE of string option;	(*need more input (prompt)*)
 exception FAIL of string option;	(*try alternatives (reason of failure)*)
 exception ABORT of string;		(*dead end*)
 
@@ -153,6 +154,7 @@
 fun try scan xs = scan xs handle MORE _ => raise FAIL None | ABORT _ => raise FAIL None;
 fun force scan xs = scan xs handle MORE _ => raise FAIL None;
 fun prompt str scan xs = scan xs handle MORE None => raise MORE (Some str);
+fun catch scan xs = scan xs handle ABORT msg => raise FAIL (Some msg);
 fun error scan xs = scan xs handle ABORT msg => Library.error msg;
 
 
@@ -179,24 +181,33 @@
 
 (* infinite scans -- draining state-based source *)
 
-fun source' def_prmpt get unget stopper scan (state, src) =
+fun drain def_prmpt get stopper scan ((state, xs), src) =
+  (scan (state, xs), src) handle MORE prmpt =>
+    (case get (if_none prmpt def_prmpt) src of
+      ([], _) => (finite' stopper scan (state, xs), src)
+    | (xs', src') => drain def_prmpt get stopper scan ((state, xs @ xs'), src'));
+
+fun source' def_prmpt get unget stopper scanner opt_recover (state, src) =
   let
-    fun drain (xs, s) =
-      (scan (state, xs), s) handle MORE prmpt =>
-        (case get (if_none prmpt def_prmpt) s of
-          ([], _) => (finite' stopper scan (state, xs), s)
-        | (xs', s') => drain (xs @ xs', s'));
+    val drain_with = drain def_prmpt get stopper;
+
+    fun drain_loop recover inp =
+      drain_with (catch scanner) inp handle FAIL msg =>
+        (warning (if_none msg "Syntax error."); warning "Trying to recover ...";
+          drain_loop recover (apfst snd (drain_with recover inp)));
 
-    val ((ys, (state', rest)), src') =
-      (case get def_prmpt src of
-        ([], s) => (([], (state, [])), s)
-      | xs_s => drain xs_s);
+    val ((ys, (state', xs')), src') =
+      (case (get def_prmpt src, opt_recover) of
+        (([], s), _) => (([], (state, [])), s)
+      | ((xs, s), None) => drain_with (error scanner) ((state, xs), s)
+      | ((xs, s), Some scan) => drain_loop scan ((state, xs), s));
   in
-    (ys, (state', unget (rest, src')))
+    (ys, (state', unget (xs', src')))
   end;
 
-fun source def_prmpt get unget stopper scan src =
-  let val (ys, ((), src')) = source' def_prmpt get unget stopper (lift scan) ((), src)
+fun source def_prmpt get unget stopper scan opt_recover src =
+  let val (ys, ((), src')) =
+    source' def_prmpt get unget stopper (lift scan) (apsome lift opt_recover) ((), src)
   in (ys, src') end;
 
 fun single scan = scan >> (fn x => [x]);