From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from weis@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id VAA08033 for caml-redistribution; Fri, 28 Nov 1997 21:40:27 +0100 (MET) Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id UAA15692 for ; Thu, 27 Nov 1997 20:45:45 +0100 (MET) Received: from jaune.inria.fr (ddr@jaune.inria.fr [128.93.11.80]) by nez-perce.inria.fr (8.8.7/8.8.5) with ESMTP id UAA13189 for ; Thu, 27 Nov 1997 20:45:43 +0100 (MET) Received: (from ddr@localhost) by jaune.inria.fr (8.8.5/8.8.5) id UAA26631; Thu, 27 Nov 1997 20:45:55 +0100 Message-Id: <199711271945.UAA26631@jaune.inria.fr> Subject: Re: hacks using camlp4 In-Reply-To: from David Monniaux at "Nov 26, 97 07:00:58 pm" To: David.Monniaux@ens-lyon.fr (David Monniaux) Date: Thu, 27 Nov 1997 20:45:55 +0100 (MET) Cc: caml-list@inria.fr From: Daniel de Rauglaudre X-Mailer: ELM [version 2.4ME+ PL28 (25)] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: weis > I lately checked the camlp4 preprocessor. I think this tool may have lots > of useful applications, since it allows especially custom syntaxes for the > input of certain kind of objects, in a more programmer-friendly fashion > than just inputting raw data structures into the source code. > > ... > > I therefore have three problems: > > 1. Precompiled expressions. > More generally, what would be needed would be some construction to > evaluate an expression as soon as it is possible. > > 2. It would be nice if regexp precompilation could be done at compile or > preprocessing time (I was thinking of marshalling the precompiled > regexp, but I fear some C-library private data structure inside the > regexp type). A solution is partial evaluation. I have implemented a syntax solution below (working with ocaml syntax, not righteous one). The idea is to automatically generate global declarations. The important file is "partial.ml" which gives a general mechanism of partial evaluations, in Ocaml (not righteous) syntax. The function "Partial.eval" generates a global variable and returns a (syntax) access to it. Then, an example: partially evaluate strings concatenation (^) when both parameters are pure strings. The file "concat.ml" changes the predefined string concatenation to generate a global variable in the interesting case. Once these files compiled (see their sources further), here is an example: $ cat foo.ml let foo x = function 0 -> x | 1 -> x ^ "aa" | 2 -> "aa" ^ x | _ -> "aa" ^ "bb" ;; No partial evaluation: $ camlp4o pr_o.cmo foo.ml let foo x = function 0 -> x | 1 -> x ^ "aa" | 2 -> "aa" ^ x | _ -> "aa" ^ "bb" ;; Partial evaluation, automatically generated by partial.cmo + concat.cmo $ camlp4o pr_o.cmo ./partial.cmo ./concat.cmo foo.ml let v_1 = "aa" ^ "bb";; let foo x = function 0 -> x | 1 -> x ^ "aa" | 2 -> "aa" ^ x | _ -> v_1 ;; Remark: the last case is not pretty printed like this by Camlp4 version 1.06+1; this is just a pretty printing bug fixed in the version 1.06+2 (patches soon available in the ftp distribution). Anyway, it works. Now, the files "partial.ml" and "concat.ml": ========================= partial.ml open Pcaml;; Grammar.warning_verbose := false;; let o2b = function Some _ -> True | None -> False;; (* Global declarations generated *) let globals = ref [];; let add_globals loc si = match !globals with [] -> si | g -> globals := []; <:str_item< declare $list:g @ [si]$ end >> ;; (* Changes the declarations which holds expressions (cf etc/pa_o.ml) in order to declare before the possible global declarations *) EXTEND str_item: [ [ "let"; r = OPT "rec"; "_"; "="; e = expr -> add_globals loc <:str_item< $exp:e$ >> | "let"; r = OPT "rec"; l = LIST1 let_binding SEP "and"; "in"; x = expr -> let e = <:expr< let $rec:o2b r$ $list:l$ in $x$ >> in add_globals loc <:str_item< $exp:e$ >> | "let"; r = OPT "rec"; l = LIST1 let_binding SEP "and" -> add_globals loc <:str_item< value $rec:o2b r$ $list:l$ >> | e = expr -> add_globals loc <:str_item< $exp:e$ >> ] ] ; END;; (* Generates a global variable name. If conflict with program variables, the user must change the "v_" into something else. *) let genvar = let cnt = ref 0 in fun () -> incr cnt; "v_" ^ string_of_int !cnt ;; (* [Partial.eval loc e] generates a global variable equal to [e] and returns an access to it; [loc] is the location of [e] for possible semantic errors *) let eval loc e = let v = genvar () in globals := !globals @ [ <:str_item< value $lid:v$ = $e$ >> ]; <:expr< $lid:v$ >> ;; ========================= concat.ml open Pcaml;; (* Changes the syntax of "^" (cf etc/pa_o.ml) in order to generate a global variable, using [Partial.eval] when both parameters are pure strings *) EXTEND expr: LEVEL "^" [ [ e1 = expr; f = [ op = "^" -> op | op = "@" -> op ]; e2 = expr -> let e = <:expr< $lid:f$ $e1$ $e2$ >> in match f, e1, e2 with "^", <:expr< $str:_$ >>, <:expr< $str:_$ >> -> Partial.eval loc e | _ -> e ] ] ; END;; ========================= Compilations: ocamlc -pp "camlp4o pa_extend.cmo q_MLast.cmo" -I `camlp4 -where` -c partial.ml ocamlc -pp "camlp4o pa_extend.cmo q_MLast.cmo" -I `camlp4 -where` -c concat.ml -------------------------------------------------------------------------- Daniel de RAUGLAUDRE Projet Cristal - INRIA Rocquencourt Tel: +33 (01) 39 63 53 51 Email: daniel.de_rauglaudre@inria.fr Web: http://pauillac.inria.fr/~ddr/ --------------------------------------------------------------------------