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.1 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 D9556BC6D for ; Mon, 17 Dec 2007 10:11:11 +0100 (CET) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAALfLZUfRSbJfn2dsb2JhbACCb40WAQEBAQcEBgkgmCI X-IronPort-AV: E=Sophos;i="4.24,175,1196636400"; d="scan'208";a="5270220" Received: from concorde.inria.fr ([192.93.2.39]) by mail2-smtp-roc.national.inria.fr with ESMTP; 17 Dec 2007 10:11:11 +0100 Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by concorde.inria.fr (8.13.6/8.13.6) with ESMTP id lBH9BBAn025977 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Mon, 17 Dec 2007 10:11:11 +0100 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAALfLZUfRSbJfn2dsb2JhbACCb40WAQEBAQcEBgkgmCI X-IronPort-AV: E=Sophos;i="4.24,175,1196636400"; d="scan'208";a="5270219" Received: from web60112.mail.yahoo.com ([209.73.178.95]) by mail2-smtp-roc.national.inria.fr with SMTP; 17 Dec 2007 10:11:10 +0100 Received: (qmail 93824 invoked by uid 60001); 17 Dec 2007 09:11:09 -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=b3ZZoOJPXW+TCZOFY5D7Zv0D+dn2R8FBVTwKMyhG4KFi9Lu3l1JKAW3ZCyVz3S03f63qA9yeWEEbz/RJE2yFcAW5r2abEOZn7oWvQhN18nGv8gEhYSuWEBCh8fr4IVmIcwdUv0ZFKXzHtyRj//XlmNMs/8ikNcvUSgxoPRvjNlM=; X-YMail-OSG: OzYmc0gVM1md9vViPkklPh2re6tgyi.bgVf221jkhpiURhzYxCosSGFF1ZSH8QOONYFhE_ouTXkoWlEtzHcpYsNtZ4G0VFhJ6dHn7qULLYOXjhmUNcN2CUgR9iREteY- Received: from [66.100.224.174] by web60112.mail.yahoo.com via HTTP; Mon, 17 Dec 2007 01:11:09 PST Date: Mon, 17 Dec 2007 01:11:09 -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-1721118192-1197882669=:92669" Content-Transfer-Encoding: 8bit Message-ID: <518979.92669.qm@web60112.mail.yahoo.com> X-Miltered: at concorde with ID 47663D2F.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 checker:01 expr:01 expr:01 ocamlc:01 camlp:01 -pp:01 --0-1721118192-1197882669=:92669 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Without quotations, the code looks like: --------------------------------------- $ cat alg.ml #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;; 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,floc)=lident; "("; xs=LIST1 SELF SEP ","; ")"->PApp (floc,f,xs)]]; lident: [[x = LIDENT -> (x, loc)]]; END;; let parse s = Grammar.Entry.parse exp_eoi (Stream.of_string s);; (* Type Checker *) exception TypeError;; type integer=[`Int];; type real=[integer | `Real];; let rec type_expr=function | PApp (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) | PInt _ -> `Int | PFlo _ -> `Real ;; (* Quotations *) type alg= | App of string*alg list | Int of int | Flo of float;; let loc=Ploc.dummy;; let rec to_expr=function | PInt (loc,x)-> <:expr< Alg.Int $int:x$ >> | PFlo (loc,x)-> <:expr< Alg.Flo $flo:x$ >> | PApp (loc,f,el)-> 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< Alg.App ($str:f$,$el$) >> ;; let rec to_patt=function | PInt (loc,x)-> <:patt< Alg.Int $int:x$ >> | PFlo (loc,x)-> <:patt< Alg.Flo $flo:x$ >> | PApp (loc,f,el)-> 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< Alg.App ($str:f$,$el$) >> ;; let expand_expr s= let p=parse s in let t=type_expr p in to_expr p ;; let expand_patt s= let p=parse s in let t=type_expr p in to_patt p ;; Quotation.add "exp" (Quotation.ExAst (expand_expr,expand_patt));; --------------------------------------- When run on the test file: --------------------------------------- $ cat test.ml let x=2;; let x=3;; let x=4;; let y= <:exp< add(1,2,3) >>;; --------------------------------------- We receive the error: --------------------------------------- ocamlc -I +camlp5 -pp "camlp5o ./alg.cmo" test.ml -o test File "test.ml", line 4, characters 14-17: While expanding quotation "exp": Uncaught exception: Alg.TypeError Preprocessor error make: *** [all] Error 2 --------------------------------------- This is a good error message and exactly what I want. Now, we modify the above code to add quotations: --------------------------------------- $ cat alg.ml #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,floc)=lident; "("; xs=LIST1 SELF SEP ","; ")"-> PApp (floc,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< Alg.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< Alg.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< Alg.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< Alg.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< Alg.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< Alg.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 ;; --------------------------------------- Then, we use this program with the test file: --------------------------------------- $ cat test.ml let x=2;; let x=3;; let x=4;; let y= <:exp< add(1,2,3) >>;; let z= Alg.type_expr y;; --------------------------------------- Everything compiles fine since we no longer type check during compilation: --------------------------------------- ocamlc -I +camlp5 -pp "camlp5o ./alg.cmo" camlp5.cma alg.cmo test.ml -o test --------------------------------------- However, when we run the following executable, we receive the error: --------------------------------------- $ ./test Fatal error: exception Ploc.Exc(_, _) --------------------------------------- This contains no location information since Plot.Exc is not caught and handled in the same manner as it is during preprocessing. I would like an error similar to the first case, when there were no quotations, to be shown in the second case, when there are quotations. Thanks for your help. --------------------------------- Looking for last minute shopping deals? Find them fast with Yahoo! Search. --0-1721118192-1197882669=:92669 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Without quotations, the code looks like:

---------------------------------------
$ cat alg.ml
#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;;


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,floc)=lident; "("; xs=LIST1 SELF SEP ","; ")"->PApp (floc,f,xs)]];
    lident:
        [[x = LIDENT -> (x, loc)]];
END;;

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

(* Type Checker *)
exception TypeError;;
type integer=[`Int];;
type real=[integer | `Real];;
let rec type_expr=function
    | PApp (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)
    | PInt _ -> `Int
    | PFlo _ -> `Real
;;


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

let loc=Ploc.dummy;;
let rec to_expr=function
    | PInt (loc,x)-> <:expr< Alg.Int $int:x$ >>
    | PFlo (loc,x)-> <:expr< Alg.Flo $flo:x$ >>
    | PApp (loc,f,el)->
        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< Alg.App ($str:f$,$el$) >>
;;
let rec to_patt=function
    | PInt (loc,x)-> <:patt< Alg.Int $int:x$ >>
    | PFlo (loc,x)-> <:patt< Alg.Flo $flo:x$ >>
    | PApp (loc,f,el)->
        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< Alg.App ($str:f$,$el$) >>
;;

let expand_expr s=
    let p=parse s in
    let t=type_expr p in
    to_expr p
;;
let expand_patt s=
    let p=parse s in
    let t=type_expr p in
    to_patt p
;;
Quotation.add "exp" (Quotation.ExAst (expand_expr,expand_patt));;
---------------------------------------

When run on the test file:

---------------------------------------
 $ cat test.ml
let x=2;;
let x=3;;
let x=4;;
let y= <:exp< add(1,2,3) >>;;
---------------------------------------

We receive the error:

---------------------------------------
ocamlc -I +camlp5 -pp "camlp5o ./alg.cmo" test.ml -o test
File "test.ml", line 4, characters 14-17:
While expanding quotation "exp":
Uncaught exception: Alg.TypeError
Preprocessor error
make: *** [all] Error 2
---------------------------------------

This is a good error message and exactly what I want.  Now, we modify the above code to add quotations:

---------------------------------------
$ cat alg.ml
#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,floc)=lident; "("; xs=LIST1 SELF SEP ","; ")"-> PApp (floc,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< Alg.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< Alg.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< Alg.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< Alg.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< Alg.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< Alg.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
;;
---------------------------------------

Then, we use this program with the test file:

---------------------------------------
$ cat test.ml
let x=2;;
let x=3;;
let x=4;;
let y= <:exp< add(1,2,3) >>;;
let z= Alg.type_expr y;;
---------------------------------------

Everything compiles fine since we no longer type check during compilation:

---------------------------------------
ocamlc -I +camlp5 -pp "camlp5o ./alg.cmo" camlp5.cma alg.cmo test.ml -o test
---------------------------------------

However, when we run the following executable, we receive the error:

---------------------------------------
$ ./test
Fatal error: exception Ploc.Exc(_, _)
---------------------------------------

This contains no location information since Plot.Exc is not caught and handled in the same manner as it is during preprocessing.  I would like an error similar to the first case, when there were no quotations, to be shown in the second case, when there are quotations.

Thanks for your help.


Looking for last minute shopping deals? Find them fast with Yahoo! Search. --0-1721118192-1197882669=:92669--