mirror of
https://github.com/c-cube/iter.git
synced 2025-12-06 11:15:32 -05:00
S-expression module, with a strong accent on
sequences (o'rly?). S-exprs can be converted to and from streams of 'tokens'
This commit is contained in:
parent
28332a45df
commit
14d651b836
3 changed files with 175 additions and 1 deletions
113
sexpr.ml
Normal file
113
sexpr.ml
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
(*
|
||||||
|
Zipperposition: a functional superposition prover for prototyping
|
||||||
|
Copyright (C) 2012 Simon Cruanes
|
||||||
|
|
||||||
|
This is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
02110-1301 USA.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(* {1 Basic S-expressions, with printing and parsing} *)
|
||||||
|
|
||||||
|
(** S-expression *)
|
||||||
|
type t =
|
||||||
|
| Atom of string (** An atom *)
|
||||||
|
| List of t list (** A list of S-expressions *)
|
||||||
|
|
||||||
|
(** Token that compose a Sexpr once serialized *)
|
||||||
|
type token = [`Open | `Close | `Atom of string]
|
||||||
|
|
||||||
|
(** Iterate on the S-expression, calling the callback with tokens *)
|
||||||
|
let rec iter f s = match s with
|
||||||
|
| Atom a -> f (`Atom a)
|
||||||
|
| List l -> f `Open; iter_list f l; f `Close
|
||||||
|
and iter_list f l = match l with
|
||||||
|
| [] -> ()
|
||||||
|
| x::l' -> iter f x; iter_list f l'
|
||||||
|
|
||||||
|
(** Traverse. This yields a sequence of tokens *)
|
||||||
|
let traverse s = Sequence.from_iter (fun k -> iter k s)
|
||||||
|
|
||||||
|
(** Lex: create a sequence of tokens from the given in_channel. *)
|
||||||
|
let lex input =
|
||||||
|
let seq_fun k =
|
||||||
|
let in_word = ref false in
|
||||||
|
let buf = Buffer.create 128 in
|
||||||
|
(* loop. TODO handle escaping of (), and "" *)
|
||||||
|
let rec next c =
|
||||||
|
match c with
|
||||||
|
| '(' -> k `Open
|
||||||
|
| ')' -> flush_word(); k `Close
|
||||||
|
| ' ' | '\t' | '\n' -> flush_word ()
|
||||||
|
| c -> in_word := true; Buffer.add_char buf c
|
||||||
|
(* finish the previous word token *)
|
||||||
|
and flush_word () =
|
||||||
|
if !in_word then begin
|
||||||
|
(* this whitespace follows a word *)
|
||||||
|
let word = Buffer.contents buf in
|
||||||
|
Buffer.clear buf;
|
||||||
|
in_word := false;
|
||||||
|
k (`Atom word)
|
||||||
|
end
|
||||||
|
in
|
||||||
|
Sequence.iter next input
|
||||||
|
in
|
||||||
|
Sequence.from_iter seq_fun
|
||||||
|
|
||||||
|
(** Build a Sexpr from a sequence of tokens *)
|
||||||
|
let of_seq seq =
|
||||||
|
(* called on every token *)
|
||||||
|
let rec k stack token = match token with
|
||||||
|
| `Open -> `Open :: stack
|
||||||
|
| `Close -> collapse [] stack
|
||||||
|
| `Atom a -> (`Expr (Atom a)) :: stack
|
||||||
|
(* collapse last list into an `Expr *)
|
||||||
|
and collapse acc stack = match stack with
|
||||||
|
| `Open::stack' -> `Expr (List acc) :: stack'
|
||||||
|
| `Expr a::stack' -> collapse (a :: acc) stack'
|
||||||
|
| _ -> assert false
|
||||||
|
in
|
||||||
|
(* iterate on the sequence, given an empty initial stack *)
|
||||||
|
let stack = Sequence.fold k [] seq in
|
||||||
|
(* stack should contain exactly one expression *)
|
||||||
|
match stack with
|
||||||
|
| [`Expr expr] -> expr
|
||||||
|
| [] -> failwith "no Sexpr could be parsed"
|
||||||
|
| _ -> failwith "too many elements on the stack"
|
||||||
|
|
||||||
|
(** Print a token on the given formatter *)
|
||||||
|
let pp_token formatter token = match token with
|
||||||
|
| `Open -> Format.fprintf formatter "@[("
|
||||||
|
| `Close -> Format.fprintf formatter ")@]"
|
||||||
|
| `Atom s -> Format.pp_print_string formatter s
|
||||||
|
|
||||||
|
(** Print a sequence of Sexpr tokens on the given formatter *)
|
||||||
|
let pp_tokens formatter tokens =
|
||||||
|
let first = ref true in
|
||||||
|
Sequence.iter
|
||||||
|
(fun token ->
|
||||||
|
(match token with
|
||||||
|
| `Open -> (if not !first then Format.fprintf formatter " "); first := true
|
||||||
|
| `Close -> first := false
|
||||||
|
| _ -> if !first then first := false else Format.fprintf formatter " ");
|
||||||
|
pp_token formatter token)
|
||||||
|
tokens
|
||||||
|
|
||||||
|
(** Pretty-print the S-expr. If [indent] is true, the S-expression
|
||||||
|
is printed with indentation. *)
|
||||||
|
let pp_sexpr ?(indent=false) formatter s =
|
||||||
|
if indent
|
||||||
|
then Format.fprintf formatter "@[<hov 4>%a@]" pp_tokens (traverse s)
|
||||||
|
else pp_tokens formatter (traverse s)
|
||||||
|
|
||||||
57
sexpr.mli
Normal file
57
sexpr.mli
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
(*
|
||||||
|
Zipperposition: a functional superposition prover for prototyping
|
||||||
|
Copyright (C) 2012 Simon Cruanes
|
||||||
|
|
||||||
|
This is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
02110-1301 USA.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(* {1 Basic S-expressions, with printing and parsing} *)
|
||||||
|
|
||||||
|
type t =
|
||||||
|
| Atom of string (** An atom *)
|
||||||
|
| List of t list (** A list of S-expressions *)
|
||||||
|
(** S-expression *)
|
||||||
|
|
||||||
|
type token = [`Open | `Close | `Atom of string]
|
||||||
|
(** Token that compose a Sexpr once serialized *)
|
||||||
|
|
||||||
|
(** {2 Traverse a sequence of tokens} *)
|
||||||
|
|
||||||
|
val iter : (token -> unit) -> t -> unit
|
||||||
|
(** Iterate on the S-expression, calling the callback with tokens *)
|
||||||
|
|
||||||
|
val traverse : t -> token Sequence.t
|
||||||
|
(** Traverse. This yields a sequence of tokens *)
|
||||||
|
|
||||||
|
(** {2 Text <-> tokens} *)
|
||||||
|
|
||||||
|
val lex : char Sequence.t -> token Sequence.t
|
||||||
|
(** Lex: create a sequence of tokens from the given sequence of chars. *)
|
||||||
|
|
||||||
|
val of_seq : token Sequence.t -> t
|
||||||
|
(** Build a Sexpr from a sequence of tokens, or raise Failure *)
|
||||||
|
|
||||||
|
(** {2 Printing} *)
|
||||||
|
|
||||||
|
val pp_token : Format.formatter -> token -> unit
|
||||||
|
(** Print a token on the given formatter *)
|
||||||
|
|
||||||
|
val pp_tokens : Format.formatter -> token Sequence.t -> unit
|
||||||
|
(** Print a sequence of Sexpr tokens on the given formatter *)
|
||||||
|
|
||||||
|
val pp_sexpr : ?indent:bool -> Format.formatter -> t -> unit
|
||||||
|
(** Pretty-print the S-expr. If [indent] is true, the S-expression
|
||||||
|
is printed with indentation. *)
|
||||||
6
tests.ml
6
tests.ml
|
|
@ -9,6 +9,8 @@ let pp_list ?(sep=", ") pp_item formatter l =
|
||||||
module ISet = Set.Make(struct type t = int let compare = compare end)
|
module ISet = Set.Make(struct type t = int let compare = compare end)
|
||||||
module ISetSeq = Sequence.Set(ISet)
|
module ISetSeq = Sequence.Set(ISet)
|
||||||
|
|
||||||
|
let sexpr = "(foo bar (bazz quux hello 42) world (zoo foo bar (1 2 (3 4))))"
|
||||||
|
|
||||||
let _ =
|
let _ =
|
||||||
let l = [0;1;2;3;4;5;6] in
|
let l = [0;1;2;3;4;5;6] in
|
||||||
let l' = Sequence.List.of_seq
|
let l' = Sequence.List.of_seq
|
||||||
|
|
@ -38,8 +40,10 @@ let _ =
|
||||||
(Sequence.Array.of_seq (Sequence.append
|
(Sequence.Array.of_seq (Sequence.append
|
||||||
(Sequence.take 5 (Sequence.List.to_seq l3)) (Sequence.List.to_seq l4))));
|
(Sequence.take 5 (Sequence.List.to_seq l3)) (Sequence.List.to_seq l4))));
|
||||||
(* sum *)
|
(* sum *)
|
||||||
let n = 200000000 in
|
let n = 100000000 in
|
||||||
let sum = Sequence.fold (+) 0 (Sequence.take n (Sequence.Int.repeat 1)) in
|
let sum = Sequence.fold (+) 0 (Sequence.take n (Sequence.Int.repeat 1)) in
|
||||||
Format.printf "%dx1 = %d@." n sum;
|
Format.printf "%dx1 = %d@." n sum;
|
||||||
assert (n=sum);
|
assert (n=sum);
|
||||||
|
let s = Sexpr.of_seq (Sexpr.lex (Sequence.String.to_seq sexpr)) in
|
||||||
|
Format.printf "parse @[<h>%s@] into @[<h>%a@]@." sexpr (Sexpr.pp_sexpr ~indent:false) s;
|
||||||
()
|
()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue