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.3 required=5.0 tests=AWL,DNS_FROM_RFC_ABUSE, DNS_FROM_RFC_WHOIS,HTML_MESSAGE autolearn=disabled version=3.1.3 Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by yquem.inria.fr (Postfix) with ESMTP id 400FDBC6B for ; Sat, 15 Dec 2007 20:32:57 +0100 (CET) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAADS7Y0fRSbJZl2dsb2JhbACCb40SAQEBAQcEBgkIEQeBFJZt X-IronPort-AV: E=Sophos;i="4.24,172,1196636400"; d="scan'208";a="5684473" Received: from concorde.inria.fr ([192.93.2.39]) by mail1-smtp-roc.national.inria.fr with ESMTP; 15 Dec 2007 20:32:57 +0100 Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by concorde.inria.fr (8.13.6/8.13.6) with ESMTP id lBFJWpad010133 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Sat, 15 Dec 2007 20:32:57 +0100 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAADS7Y0fRSbJZl2dsb2JhbACCb40SAQEBAQcEBgkIEQeBFJZt X-IronPort-AV: E=Sophos;i="4.24,172,1196636400"; d="scan'208";a="5684472" Received: from web60121.mail.yahoo.com ([209.73.178.89]) by mail1-smtp-roc.national.inria.fr with SMTP; 15 Dec 2007 20:32:56 +0100 Received: (qmail 55409 invoked by uid 60001); 15 Dec 2007 19:32:55 -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=Hn/6g/QOJ/tZRSP64aKD3T3KVjNfyBG+UA3NZY13pzvCwXAHlH327TId5h7v7JeL5Z/IqyF1H6Aydqld1yfpCjR3KRLXDQUrprQb/u5RRguIK7RJndT91HxDa6iIzdZH1JHqU4aYplXHVpyEQ3qdxo96L93MXbXECFACzyy5ekw=; X-YMail-OSG: 8F_a71kVM1mcU5vRdLwnyzmm.FK6CGsAvzqleANt2IbZlL18nRldHLFStW8ytOKcKY_E1ZSq53G1l9TDVU1KkxX4bTkRoIsL53w0jn.PgUvfcUBlz1kZ Received: from [66.100.224.174] by web60121.mail.yahoo.com via HTTP; Sat, 15 Dec 2007 11:32:55 PST Date: Sat, 15 Dec 2007 11:32:55 -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-516671972-1197747175=:53415" Content-Transfer-Encoding: 8bit Message-ID: <266122.53415.qm@web60121.mail.yahoo.com> X-Miltered: at concorde with ID 47642BE3.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; camlp:01 parser:01 checker:01 cmo:01 mlast:01 cmo:01 parser:01 plexer:01 gmake:01 lident:01 checker:01 expr:01 expr:01 datatype:01 runtime:01 --0-516671972-1197747175=:53415 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Allow me to clarify what I meant by type errors and antiquotations. Here is a very simple program that contains the parser, type checker, and quotation generator: --------------------------------------- #load "pa_extend.cmo";; #load "q_MLast.cmo";; (* Parser *) type palg= | PApp of string*palg list | PInt of string | PFlo of 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 x | x=FLOAT -> PFlo x | f = LIDENT; "("; xs=LIST1 SELF SEP ","; ")"-> PApp (f,xs)]]; 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 (f,args) -> (match f with | "add" -> if List.length args != 2 then raise 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) | _ -> raise 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 x-> <:expr< Int $int:x$ >> | PFlo x-> <:expr< Flo $flo:x$ >> | PApp (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< App ($str:f$,$el$) >> ;; let rec to_patt=function | PInt x-> <:patt< Int $int:x$ >> | PFlo x-> <:patt< Flo $flo:x$ >> | PApp (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< 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));; --------------------------------------- Thus, by type check, I mean actually verifying the typing rules of the DSL. In this case, it means that the only function allowed is "add" and that this function requires two arguments. Now, imagine the above language where antiquotations are allowed. The parsed AST would have datatype type palg= | PApp of string*palg list | PInt of string | PFlo of string | PQuote of Ploc.t*string and it becomes impossible to type check in the above sense since we can not ascertain the type of PQuote. Now, we can still type check the resulting AST of type alg (not palg). But, this must occur at runtime rather than during the preprocessing step at compile time. Therein lies the problem. If we discover a type error during runtime, it would be nice to give the user some indication of where the error occurs short of saying, "Add expects two arguments." Since the location information provided is relative to the quote, it can still be challenging to determine exactly where the type error occurs. Thus, I'm either trying to obtain better location information or perhaps learn that there's a better place or method to type check than what I'm using. --------------------------------- Never miss a thing. Make Yahoo your homepage. --0-516671972-1197747175=:53415 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Allow me to clarify what I meant by type errors and antiquotations.  Here is a very simple program that contains the parser, type checker, and quotation generator:

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

(* Parser *)
type palg=
| PApp of string*palg list
| PInt of string
| PFlo of 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 x
        | x=FLOAT -> PFlo x
        | f = LIDENT; "("; xs=LIST1 SELF SEP ","; ")"-> PApp (f,xs)]];
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 (f,args) ->
        (match f with
        | "add" ->
            if List.length args != 2 then
                raise 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)
        | _ -> raise 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 x-> <:expr< Int $int:x$ >>
    | PFlo x-> <:expr< Flo $flo:x$ >>
    | PApp (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< App ($str:f$,$el$) >>
;;
let rec to_patt=function
    | PInt x-> <:patt< Int $int:x$ >>
    | PFlo x-> <:patt< Flo $flo:x$ >>
    | PApp (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< 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));;
---------------------------------------

Thus, by type check, I mean actually verifying the typing rules of the DSL.  In this case, it means that the only function allowed is "add" and that this function requires two arguments.  Now, imagine the above language where antiquotations are allowed.  The parsed AST would have datatype

type palg=
| PApp of string*palg list
| PInt of string
| PFlo of string
| PQuote of Ploc.t*string

and it becomes impossible to type check in the above sense since we can not ascertain the type of PQuote.  Now, we can still type check the resulting AST of type alg (not palg).  But, this must occur at runtime rather than during the preprocessing step at compile time.  Therein lies the problem.

If we discover a type error during runtime, it would be nice to give the user some indication of where the error occurs short of saying, "Add expects two arguments."  Since the location information provided is relative to the quote, it can still be challenging to determine exactly where the type error occurs.  Thus, I'm either trying to obtain better location information or perhaps learn that there's a better place or method to type check than what I'm using.


Never miss a thing. Make Yahoo your homepage. --0-516671972-1197747175=:53415--