From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: * X-Spam-Status: No, score=1.2 required=5.0 tests=AWL,DNS_FROM_RFC_ABUSE, DNS_FROM_RFC_WHOIS,HTML_MESSAGE autolearn=disabled version=3.1.3 Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by yquem.inria.fr (Postfix) with ESMTP id 1B3DDBC69 for ; Mon, 17 Dec 2007 04:29:28 +0100 (CET) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAAAZ8ZUfAXQImh2dsb2JhbACCb40WAQEBCAopmEo X-IronPort-AV: E=Sophos;i="4.24,174,1196636400"; d="scan'208";a="5265124" Received: from discorde.inria.fr ([192.93.2.38]) by mail2-smtp-roc.national.inria.fr with ESMTP; 17 Dec 2007 04:29:27 +0100 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by discorde.inria.fr (8.13.6/8.13.6) with ESMTP id lBH3TRdW007865 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Mon, 17 Dec 2007 04:29:27 +0100 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAAMp7ZUfRSbJXn2dsb2JhbACCb40WAQEBAQcEBgkgmE8 X-IronPort-AV: E=Sophos;i="4.24,174,1196636400"; d="scan'208";a="20386808" Received: from web60119.mail.yahoo.com ([209.73.178.87]) by mail4-smtp-sop.national.inria.fr with SMTP; 17 Dec 2007 04:29:26 +0100 Received: (qmail 28427 invoked by uid 60001); 17 Dec 2007 03:29:25 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.com; h=X-YMail-OSG:Received:Date:From:Subject:To:In-Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-ID; b=nae+fxx+uxnkYuQVmQ9Bqgno2F8/ycTGiB+vyOWWfDGw8oU8NpnFTb1CiERi633HBdZ/2ri8LV6Rrzw6tPBvDDz1pgwoRrYjFyKDJKCer5k3WqN+O1RtzbC2cZFdctN9+Lm0tSn4BpsmNJh9Ko/xnp0mXMreYS72zkoIFkCPDFk=; X-YMail-OSG: ps9.ROQVM1n6AF4GY8mdKUA4zQUDqPCLv6PfXQZQQMIpZZ3PRbveQXszyrDbDJRKFZkoYN6PWyslYpQOjy4L5xhYguuCEk7KcEoye_cw06gpjGArlmgj Received: from [66.100.224.174] by web60119.mail.yahoo.com via HTTP; Sun, 16 Dec 2007 19:29:24 PST Date: Sun, 16 Dec 2007 19:29:24 -0800 (PST) From: echinuz echinuz Subject: Re: [Caml-list] How to Create Sensible Debugging Information when Dynamically Typechecking Code Generated with camlp5 Quotations To: caml-list@inria.fr In-Reply-To: <1197733590-sup-3933@ausone.local> MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="0-1431069550-1197862164=:27694" Content-Transfer-Encoding: 8bit Message-ID: <926126.27694.qm@web60119.mail.yahoo.com> X-Miltered: at discorde with ID 4765ED17.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; camlp:01 cmo:01 mlast:01 cmo:01 parser:01 plexer:01 gmake:01 lident:01 lident:01 expr:01 expr:01 pcaml:01 pcaml:01 checker:01 integers:01 --0-1431069550-1197862164=:27694 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit That's very close to what I'd like, but quotations cause a problem. With quotations, it's impossible to type check during preprocessing. It must occur after the AST has been formed. In this case, Ploc.raise doesn't generate nice error messages like it does during preprocessing. Here's the offending code: ------------------------------ #load "pa_extend.cmo";; #load "q_MLast.cmo";; (* Parser *) type palg= | PApp of Ploc.t*string*palg list | PInt of Ploc.t*string | PFlo of Ploc.t*string | PQuote of Ploc.t*string;; let g=Grammar.gcreate (Plexer.gmake ());; let exp_eoi = Grammar.Entry.create g "exp_eoi";; EXTEND GLOBAL: exp_eoi; exp_eoi: [[ x = exp; EOI -> x ]] ; exp: [[x=INT -> PInt (loc,x) | x=FLOAT -> PFlo (loc,x) | (f,loc)=lident; "("; xs=LIST1 SELF SEP ","; ")"-> PApp (loc,f,xs) | x=ANTIQUOT-> PQuote(loc,x)]]; lident: [[x = LIDENT -> (x, loc)]]; END;; let parse s = Grammar.Entry.parse exp_eoi (Stream.of_string s);; (* Quotations *) type alg= | App of Ploc.t*string*alg list | Int of Ploc.t*int | Flo of Ploc.t*float;; let get_loc l= string_of_int (Ploc.line_nb l), string_of_int (Ploc.bol_pos l), string_of_int (Ploc.first_pos l), string_of_int (Ploc.last_pos l) ;; let rec to_expr=function | PInt (loc,x)-> let line_nb,bol_pos,bp,ep=get_loc loc in <:expr< Int (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$), $int:x$) >> | PFlo (loc,x)-> let line_nb,bol_pos,bp,ep=get_loc loc in <:expr< Flo (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$), $flo:x$) >> | PApp (loc,f,el)-> let line_nb,bol_pos,bp,ep=get_loc loc in let rec make_el=function | x::xs -> <:expr< [$x$::$make_el xs$] >> | [] -> <:expr< [] >> in let el=List.map to_expr el in let el=make_el el in <:expr< App(Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$), $str:f$,$el$) >> | PQuote (loc,x)-> let loc=Ploc.make (Ploc.line_nb loc) (Ploc.bol_pos loc) (Ploc.first_pos loc + 1,Ploc.last_pos loc + 1) in let x=Grammar.Entry.parse Pcaml.expr_eoi (Stream.of_string x) in <:expr< $anti:x$ >> ;; let rec to_patt=function | PInt (loc,x)-> let line_nb,bol_pos,bp,ep=get_loc loc in <:patt< Int (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$), $int:x$) >> | PFlo (loc,x)-> let line_nb,bol_pos,bp,ep=get_loc loc in <:patt< Flo (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$), $flo:x$) >> | PApp (loc,f,el)-> let line_nb,bol_pos,bp,ep=get_loc loc in let rec make_el=function | x::xs -> <:patt< [$x$::$make_el xs$] >> | [] -> <:patt< [] >> in let el=List.map to_patt el in let el=make_el el in <:patt< App (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$), $str:f$,$el$) >> | PQuote (loc,x)-> let loc=Ploc.make (Ploc.line_nb loc) (Ploc.bol_pos loc) (Ploc.first_pos loc + 1,Ploc.last_pos loc + 1) in let x=Grammar.Entry.parse Pcaml.patt_eoi (Stream.of_string x) in <:patt< $anti:x$ >> ;; let expand_expr s=to_expr (parse s);; let expand_patt s=to_patt (parse s);; Quotation.add "exp" (Quotation.ExAst (expand_expr,expand_patt));; (* Type Checker *) exception TypeError;; type integer=[`Int];; type real=[integer | `Real];; let rec type_expr=function | App (loc,f,args) -> (match f with | "add" -> if List.length args != 2 then Ploc.raise loc TypeError else let args=List.map type_expr args in (match (List.nth args 0,List.nth args 1) with | #integer,#integer -> `Int | #real,#real -> `Real) | _ -> Ploc.raise loc TypeError) | Int _ -> `Int | Flo _ -> `Real ;; ------------------------------ How do you generate nice error messages with location information as they occur during preprocessing? As a corollary, is there an easier way to extract location information into the final AST other than removing each of the four integers, converting them to strings, and inserting them with antiquotations manually (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$))? --------------------------------- Never miss a thing. Make Yahoo your homepage. --0-1431069550-1197862164=:27694 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: 8bit That's very close to what I'd like, but quotations cause a problem.  With quotations, it's impossible to type check during preprocessing.  It must occur after the AST has been formed.  In this case, Ploc.raise doesn't generate nice error messages like it does during preprocessing.  Here's the offending code:

------------------------------
#load "pa_extend.cmo";;
#load "q_MLast.cmo";;

(* Parser *)
type palg=
| PApp of Ploc.t*string*palg list
| PInt of Ploc.t*string
| PFlo of Ploc.t*string
| PQuote of Ploc.t*string;;

let g=Grammar.gcreate (Plexer.gmake ());;
let exp_eoi = Grammar.Entry.create g "exp_eoi";;

EXTEND
    GLOBAL: exp_eoi;
    exp_eoi:
        [[ x = exp; EOI -> x ]] ;
    exp:
        [[x=INT -> PInt (loc,x)
        | x=FLOAT -> PFlo (loc,x)
        | (f,loc)=lident; "("; xs=LIST1 SELF SEP ","; ")"-> PApp (loc,f,xs)
        | x=ANTIQUOT-> PQuote(loc,x)]];
    lident:
        [[x = LIDENT -> (x, loc)]];
END;;

let parse s = Grammar.Entry.parse exp_eoi (Stream.of_string s);;

(* Quotations *)
type alg=
| App of Ploc.t*string*alg list
| Int of Ploc.t*int
| Flo of Ploc.t*float;;

let get_loc l=
    string_of_int (Ploc.line_nb l),
    string_of_int (Ploc.bol_pos l),
    string_of_int (Ploc.first_pos l),
    string_of_int (Ploc.last_pos l)
;;
let rec to_expr=function
    | PInt (loc,x)->
        let line_nb,bol_pos,bp,ep=get_loc loc in
        <:expr< Int (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$),
            $int:x$) >>
    | PFlo (loc,x)->
        let line_nb,bol_pos,bp,ep=get_loc loc in
        <:expr< Flo (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$),
            $flo:x$) >>
    | PApp (loc,f,el)->
        let line_nb,bol_pos,bp,ep=get_loc loc in
        let rec make_el=function
            | x::xs -> <:expr< [$x$::$make_el xs$] >>
            | [] -> <:expr< [] >>
        in
        let el=List.map to_expr el in
        let el=make_el el in
        <:expr< App(Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$),
            $str:f$,$el$) >>
    | PQuote (loc,x)->
        let loc=Ploc.make (Ploc.line_nb loc) (Ploc.bol_pos loc)
            (Ploc.first_pos loc + 1,Ploc.last_pos loc + 1)
        in
        let x=Grammar.Entry.parse Pcaml.expr_eoi (Stream.of_string x) in
        <:expr< $anti:x$ >>
;;
let rec to_patt=function
    | PInt (loc,x)->
        let line_nb,bol_pos,bp,ep=get_loc loc in
        <:patt< Int (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$),
            $int:x$) >>
    | PFlo (loc,x)->
        let line_nb,bol_pos,bp,ep=get_loc loc in
        <:patt< Flo (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$),
            $flo:x$) >>
    | PApp (loc,f,el)->
        let line_nb,bol_pos,bp,ep=get_loc loc in
        let rec make_el=function
            | x::xs -> <:patt< [$x$::$make_el xs$] >>
            | [] -> <:patt< [] >>
        in
        let el=List.map to_patt el in
        let el=make_el el in
        <:patt< App (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$),
            $str:f$,$el$) >>
    | PQuote (loc,x)->
        let loc=Ploc.make (Ploc.line_nb loc) (Ploc.bol_pos loc)
            (Ploc.first_pos loc + 1,Ploc.last_pos loc + 1)
        in
        let x=Grammar.Entry.parse Pcaml.patt_eoi (Stream.of_string x) in
        <:patt< $anti:x$ >>
;;

let expand_expr s=to_expr (parse s);;
let expand_patt s=to_patt (parse s);;

Quotation.add "exp" (Quotation.ExAst (expand_expr,expand_patt));;

(* Type Checker *)
exception TypeError;;
type integer=[`Int];;
type real=[integer | `Real];;
let rec type_expr=function
    | App (loc,f,args) ->
        (match f with
        | "add" ->
            if List.length args != 2 then
                Ploc.raise loc TypeError
            else
                let args=List.map type_expr args in
                (match (List.nth args 0,List.nth args 1) with
                | #integer,#integer -> `Int
                | #real,#real -> `Real)
        | _ -> Ploc.raise loc TypeError)
    | Int _ -> `Int
    | Flo _ -> `Real
;;
------------------------------

How do you generate nice error messages with location information as they occur during preprocessing?  As a corollary, is there an easier way to extract location information into the final AST other than removing each of the four integers, converting them to strings, and inserting them with antiquotations manually (Ploc.make $int:line_nb$ $int:bol_pos$ ($int:bp$,$int:ep$))?


Never miss a thing. Make Yahoo your homepage. --0-1431069550-1197862164=:27694--