1 (**************************************************************************)
4 (* Copyright (C) 2002 Institut National de Recherche en Informatique et *)
5 (* en Automatique. All rights reserved. *)
7 (* This program is free software; you can redistribute it and/or modify *)
8 (* it under the terms of the GNU General Public License as published by *)
9 (* the Free Software Foundation; either version 2 of the License, or *)
10 (* any later version. *)
12 (* This program is distributed in the hope that it will be useful, *)
13 (* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
14 (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
15 (* GNU General Public License for more details. *)
17 (* You should have received a copy of the GNU General Public License *)
18 (* along with this program; if not, write to the Free Software *)
19 (* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA *)
22 (* Contact: Maxence.Guesdon@inria.fr *)
23 (**************************************************************************)
28 #load "pa_extend.cmo";;
32 (** Code generation from Zoggy input *)
36 exception Field_error
of string
40 let anonymous_name_counter = ref 0
42 let gen_anonynous_name ele
=
43 if ele
.name
= "_" && ele
.children
<> [] then begin
44 incr
anonymous_name_counter;
45 ele
.name
<- Printf.sprintf
"_anonymous_container_%d"
46 !anonymous_name_counter;
51 module Zoggy
(Syntax
: Camlp4.Sig.Camlp4Syntax
) =
58 let parse_string loc
=
64 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
65 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
74 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
75 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
83 (* let strm = Stream.of_string str in *)
84 Gram.parse_string expr
loc str
87 (fun _ -> Lexing.dummy_pos, Lexing.dummy_pos)
93 Printf.eprintf
"Error in \"%s\"\n" str
; flush stderr
;
96 | Loc.Exc_located
(loc, e
) -> e
, loc
101 (** parsing a prop value *)
102 let parse_prop_value prop
=
103 (* let loc = fst prop.prop_value_loc + 1, snd prop.prop_value_loc - 1 in *)
104 parse_string prop
.prop_value_loc prop
.prop_value
106 let ast_of_class_info loc cl
=
107 let (_
, _
, _
, fonc
) = Zog_types.get_class_info cl
in parse_string loc fonc
109 (** Return the value of a property kind in a list of properties. *)
110 let ast_of_prop_value loc props kind
=
112 let p = List.find
(fun p -> p.prop_kind
= kind
) props
in
119 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
120 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
126 let get_prop_label ele prop
=
127 match prop
.prop_kind
with
131 | Padding
-> "padding"
134 | Border_width
-> "border_width"
136 | Allow_shrink
-> "allow_shrink"
137 | Allow_grow
-> "allow_grow"
138 | Auto_shrink
-> "auto_shrink"
143 | Orientation
-> "orientation"
144 | Toolbar_style
-> "style"
145 | Toolbar_space_size
-> "space_size"
146 | Toolbar_space_style
-> "space_style"
147 | Tooltips
-> "tooltips"
148 | Button_relief_style
-> "button_relief"
149 | Spacing
-> "spacing"
150 | Homogeneous
-> "homogeneous"
151 | Button_box_style
-> "layout"
152 | Child_width
-> "child_width"
153 | Child_height
-> "child_height"
154 | Child_ipadx
-> "child_ipadx"
155 | Child_ipady
-> "child_ipady"
156 | Label_xalign
-> "label_xalign"
157 | Label_yalign
-> "label_yalign"
159 begin match ele
.classe
with
163 | Obey_child
-> "obey_child"
165 | Hscrollbar_policy
-> "hpolicy"
166 | Vscrollbar_policy
-> "vpolicy"
167 | Handle_position
-> "handle_position"
168 | Snap_edge
-> "snap_edge"
169 | Column_titles
-> "titles"
170 | Show_titles
-> "titles_show"
171 | X_align
-> "xalign"
172 | Y_align
-> "yalign"
176 | Line_wrap
-> "line_wrap"
177 | Tab_pos
-> "tab_pos"
178 | Show_tabs
-> "show_tabs"
179 | Homogeneous_tabs
-> "homogeneous_tabs"
180 | Show_border
-> "show_border"
181 | Scrollable
-> "scrollable"
182 | Tab_border
-> "tab_border"
184 | SBUpdate_policy
-> "update_policy"
185 | Visibility
-> "visibility"
186 | Editable
-> "editable"
187 | Use_arrows
-> "use_arrows"
188 | Case_sensitive
-> "case_sensitive"
189 | Word_wrap
-> "word_wrap"
190 | Column_number
-> "columns"
191 | Draw_indicator
-> "draw_indicator"
193 | Placement
-> "placement"
194 | Selection_mode
-> "selection_mode"
195 | Justification
-> "justify"
196 | Max_length
-> "max_length"
197 | View_mode
-> "view_mode"
198 | View_lines
-> "view_lines"
199 | Handle_size
-> "handle_size"
202 | Accel_group_name
| Accel_modifier
| Accel_flags
| Accel_keysym
|
203 Show_toggle
| Show_indicator
| Right_justify
->
205 | Arrow_type
-> "kind"
206 | Calendar_options
-> "options"
207 | Popdown_strings
-> "popdown_strings"
208 | Value_in_list
-> "value_in_list"
209 | Ok_if_empty
-> "ok_if_empty"
210 | Update_policy
-> "update_policy"
212 | PPixmap_file
| PPixmap_data
| PPixmap_code
-> ""
214 (** Remove blanks (space, tabs, \r and \n) from a string. *)
215 let remove_blanks s
=
216 let buf = Buffer.create
16 in
219 ' '
| '
\n'
| '
\t'
| '
\r'
-> ()
221 Buffer.add_char
buf c
226 (** Indicate whether a property param must be printed.*)
229 let (_
, _
, values_kind
, _
) = Zog_types.get_prop_info prop
.prop_kind
in
230 match values_kind
with
233 begin try int_of_string prop
.prop_value
>= 0 with
234 _
-> (remove_blanks prop
.prop_value
) <> ""
236 | Float
-> (remove_blanks prop
.prop_value
) <> ""
237 | Code
| Code_list
-> (remove_blanks prop
.prop_value
) <> ""
239 | Enum
((s
, _
) :: _
) -> true
240 | Enum_list
[] -> false
241 | Enum_list
((s
, _
) :: _
) -> true
243 let v_no_blank = remove_blanks prop
.prop_value
in v_no_blank <> ""
245 Failure s
-> prerr_endline s
; false
247 let field_error_string f =
248 match List.find
(fun (x
, _
, _
, _
) -> x
= f) Zog_types.properties
with
251 let ast_of_creation_options_code (loc:Loc.t
) ele
f =
255 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
256 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
262 match prop
.prop_kind
with
263 Function
| Tab_label
| Expand
| Fill
| Padding
-> f
264 | Accel_modifier
| Accel_group_name
| Accel_flags
| Accel_keysym
| Show_toggle
|
265 Show_indicator
| Right_justify
->
268 if must_gen prop
then
269 let v = parse_prop_value prop
in
270 <:expr
< $
f$
(GDraw.pixmap_from_xpm ~file
: $
v$
()) >>
272 raise
(Field_error
(field_error_string PPixmap_file
))
274 if must_gen prop
then
275 let v = parse_prop_value prop
in
276 <:expr
< $
f$
(GDraw.pixmap_from_xpm_d ~data
: $
v$
()) >>
278 raise
(Field_error
(field_error_string PPixmap_data
))
280 if must_gen prop
then
281 let v = parse_prop_value prop
in
284 raise
(Field_error
(field_error_string PPixmap_code
))
286 if must_gen prop
then
287 let v = parse_prop_value prop
in
288 <:expr
< $
f$ ~ $
get_prop_label ele prop$
: $
v$
>>
291 List.fold_left
g f ele
.props
293 let ast_of_pack_options_code loc f ele
=
295 match prop
.prop_kind
with
296 Expand
| Fill
| Padding
->
297 if must_gen prop
then
301 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
302 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
306 let v = parse_prop_value prop
in
307 <:expr
< $
f$ ~ $
get_prop_label ele prop$
: $
v$
>>
311 List.fold_left
g f ele
.props
313 let ast_of_pack_code loc parent ele
f =
315 let pack_met = Zog_types.pack_method_of_ele parent ele
in
323 { Lexing.dummy_pos with Lexing.pos_cnum = fst parent.name_loc } ,
324 { Lexing.dummy_pos with Lexing.pos_cnum = snd parent.name_loc }
328 <:expr
< $lid
:parent
.name$
>>
334 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
335 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
345 ~text
:$
ast_of_prop_value loc1 ele
.props Tab_label$
())
350 (* let loc = parent.name_loc in *)
354 { Lexing.dummy_pos with Lexing.pos_cnum = fst parent.name_loc } ,
355 { Lexing.dummy_pos with Lexing.pos_cnum = snd parent.name_loc }
359 <:expr
< $lid
:parent
.name$
>>
365 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
366 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
370 let p x
= <:expr
< $
f$ ~packing
: $x$
>> in
372 Pack
-> p (ast_of_pack_options_code loc1 <:expr
< $
g$ # pack
>> ele
)
373 | Add
-> p <:expr
< $
g$ # add
>>
374 | Add1
-> p <:expr
< $
g$ # add1
>>
375 | Add2
-> p <:expr
< $
g$ # add2
>>
376 | Add_with_viewport
-> p <:expr
< $
g$ # add_with_viewport
>>
377 | Set_submenu
-> p <:expr
< $
g$ # set_submenu
>>
378 | Insert_page
| No_pack
-> f
384 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
385 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
390 <:expr
< $
f$ failed
>>
392 let ast_of_custom_pack_code loc parent ele ce
=
394 let pack_met = Zog_types.pack_method_of_ele parent ele
in
403 { Lexing.dummy_pos with Lexing.pos_cnum = fst parent.name_loc } ,
404 { Lexing.dummy_pos with Lexing.pos_cnum = snd parent.name_loc }
408 <:expr
< $lid
:parent
.name$
>>
414 { Lexing.dummy_pos with Lexing.pos_cnum = fst ele.name_loc } ,
415 { Lexing.dummy_pos with Lexing.pos_cnum = snd ele.name_loc }
419 <:expr
< $lid
:ele
.name$
>>
425 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
426 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
432 let _ = $
g$ # append_page
435 ~text
:$
ast_of_prop_value loc1 ele
.props
437 #coerce $
n$#coerce
in
446 { Lexing.dummy_pos with Lexing.pos_cnum = fst parent.name_loc } ,
447 { Lexing.dummy_pos with Lexing.pos_cnum = snd parent.name_loc }
451 <:expr
< $lid
:parent
.name$
>>
457 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
458 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
464 Pack
-> ast_of_pack_options_code loc1 <:expr
< $
g$ # pack
>> ele
465 | Add
-> <:expr
< $
g$ # add
>>
466 | Add1
-> <:expr
< $
g$ # add1
>>
467 | Add2
-> <:expr
< $
g$ # add2
>>
468 | Add_with_viewport
-> <:expr
< $
g$ # add_with_viewport
>>
469 | Set_submenu
-> <:expr
< $
g$ # set_submenu
>>
470 | Insert_page
| No_pack
-> g
476 { Lexing.dummy_pos with Lexing.pos_cnum = fst ele.name_loc } ,
477 { Lexing.dummy_pos with Lexing.pos_cnum = snd ele.name_loc }
481 <:expr
< $lid
:ele
.name$
>>
483 <:class_expr
< let _ = $
r$ $
n$ # coerce
in $ce$
>>
489 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
490 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
495 <:class_expr
< let _ = failed
in $ce$
>>
497 (** The accel_group variable name for the given Menubar ele. *)
498 let accel_group_name ele
=
499 let accel_group_v = Zog_types.get_prop_value ele
.props Accel_group_name
in
501 match remove_blanks accel_group_v with
502 "" -> "accel_" ^ ele
.name
507 (** Output the OCaml for the given menu_item (or check or radio)
508 and its optional submenu, to perform after creation initializations
509 like adding accelerators and fixing some properties. *)
510 let rec ast_of_post_menu_item_creation_code loc accel_name ele ce
=
511 let keysym_v = Zog_types.get_prop_value ele
.props Accel_keysym
in
513 List.fold_right
(ast_of_post_menu_creation_code
loc accel_name
)
516 match remove_blanks keysym_v with
521 remove_blanks (Zog_types.get_prop_value ele
.props Accel_modifier
)
527 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
528 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
533 | s
-> parse_string loc s
537 remove_blanks (Zog_types.get_prop_value ele
.props Accel_flags
)
543 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
544 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
549 | s
-> parse_string loc s
555 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
556 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
562 $lid
:ele
.name$ #add_accelerator ~group
: $lid
:accel_name$
563 ~modi
: $
modifier$ ~
flags: $
flags$ $
parse_string loc1 v$
567 and ast_of_post_menu_creation_code
loc accel_name ele
ce =
568 match ele
.classe
with
571 List.fold_right
(ast_of_post_menu_item_creation_code loc accel_name
)
577 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
578 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
583 let _ = $lid
:ele
.name$ #set_accel_group $lid
:accel_name$
in $
ce$
>>
586 (** Output the OCaml for the given element which must be a Menubar. *)
587 let ast_of_post_menubar_creation_code ?win
loc ele
ce =
588 match ele
.classe
with
590 let acc_name = accel_group_name ele
in
592 List.fold_right
(ast_of_post_menu_item_creation_code loc acc_name)
603 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
604 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
609 let _ = $lid
:w$#add_accel_group $lid
:acc_name$
in $
ce$
616 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
617 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
622 let $lid
:acc_name$
= GtkData.AccelGroup.create
() in
628 let rec ast_of_ele_creations ?win
loc parent_opt previous_opt ele
ce =
629 let ce = ast_of_post_menubar_creation_code ?win
loc ele
ce in
631 let rec iter prev
ce =
635 let ce = iter (Some e
) ce q
in
636 ast_of_ele_creations ?win
loc (Some ele
) prev e
ce
638 iter None
ce ele
.children
641 if ele
.classe
= Custom_box
then ast_of_prop_value loc ele
.props Function
643 let f = ast_of_class_info ele
.name_loc ele
.classe
in
644 let f = ast_of_creation_options_code loc ele
f in
646 match ele
.classe
, previous_opt
with
647 Radio_menu_item
, Some
e when e.classe
= Radio_menu_item
->
651 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
652 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
656 <:expr
< $
f$ ~group
: $lid
:e.name$ #group
>>
659 match parent_opt
with
661 | Some parent
-> ast_of_pack_code loc parent ele
f
664 if ele
.classe
= Custom_box
then
665 match parent_opt
with
667 | Some parent
-> ast_of_custom_pack_code loc parent ele
ce
671 gen_anonynous_name ele
;
672 if ele
.name = "_" then
676 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
677 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
681 <:class_expr
< let _ = $
e$
() in $
ce$
>>
688 { Lexing.dummy_pos with Lexing.pos_cnum = fst ele.name_loc } ,
689 { Lexing.dummy_pos with Lexing.pos_cnum = snd ele.name_loc }
693 <:patt
< $lid
:ele
.name$
>>
698 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
699 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
703 <:class_expr
< let $
n$
= $
e$
() in $
ce$
>>
705 let rec ast_of_ele_methods loc ele
=
707 if ele
.classe
= Menubar
then
708 let accel_name = accel_group_name ele
in
712 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
713 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
717 [ <:class_str_item
< method $
accel_name$
= $lid
:accel_name$
>> ]
721 gen_anonynous_name ele
;
722 let cil = if ele
.name.[0] <> '
_'
then
727 { Lexing.dummy_pos with Lexing.pos_cnum = fst ele.name_loc } ,
728 { Lexing.dummy_pos with Lexing.pos_cnum = snd ele.name_loc }
732 <:expr
< $lid
:ele
.name$
>>
737 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
738 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
742 <:class_str_item
< method $ele
.name$
= $
n$
>> :: cil else cil in
744 List.fold_left
(fun cil ele
-> cil @ ast_of_ele_methods loc ele
) cil
747 let rec ast_of_ele_vals loc ele
=
749 if ele
.classe
= Menubar
then
750 let accel_name = accel_group_name ele
in
754 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
755 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
759 [ <:class_str_item
< value $
accel_name$
= $lid
:accel_name$
>> ]
763 gen_anonynous_name ele
;
768 { Lexing.dummy_pos with Lexing.pos_cnum = fst ele.name_loc } ,
769 { Lexing.dummy_pos with Lexing.pos_cnum = snd ele.name_loc }
773 <:expr
< $lid
:ele
.name$
>>
775 let cil = if ele
.name.[0] <> '
_'
then
779 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
780 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
784 <:class_str_item
< value $ele
.name$
= $
n$
>> :: cil
788 List.fold_left
(fun cil ele
-> cil @ ast_of_ele_vals loc ele
) cil
791 let ast_of_entity loc entity
=
794 match entity
.en_ele
with
797 let cil = ast_of_ele_vals loc e @ ast_of_ele_methods loc e in
805 { Lexing.dummy_pos with Lexing.pos_cnum = fst e.name_loc } ,
806 { Lexing.dummy_pos with Lexing.pos_cnum = snd e.name_loc }
810 <:expr
< $lid
:e.name$
>>
815 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
816 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
820 let ci = <:class_str_item
< method coerce
= $
n$ # coerce
>> in
826 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
827 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
831 <:class_expr
@loc< object (*$None$*) $list
:cil$
end >>
834 match entity
.en_ele
with
838 match ele
.classe
with
839 Window
-> Some ele
.name
842 ast_of_ele_creations ?win
: win_opt loc None None ele
ce
847 { Lexing.dummy_pos with Lexing.pos_cnum = fst loc } ,
848 { Lexing.dummy_pos with Lexing.pos_cnum = snd loc }
853 List.fold_right
(fun p ce -> <:class_expr
< fun $lid
:p$
-> $
ce$
>>)
854 entity
.en_params
<:class_expr
< fun () -> $
ce$
>>
856 <:str_item
@loc< class $lid
:entity
.en_name$
= $
ce$
>>
858 (* Parser for Zoggy input (XML) *)
860 (* let gram = Grammar.create (Plexer.make ()) *)
861 (* let project = Gram.Entry.mk gram "project" *)
863 Gram.Entry.clear implem
;;
866 Printf.eprintf
"Error: field %s is empty\n" s
868 let eoi : '
eoi Gram.Entry.t
= Gram.Entry.mk
"eoi"
870 Gram.extend
(eoi : '
eoi Gram.Entry.t
)
875 (((function | EOI
-> true | _ -> false),
878 (fun (__camlp4_0
: Gram.Token.t
) (loc : Gram.Loc.t
)
880 match __camlp4_0
with
882 | _ -> assert false))) ]) ]))
886 (* GLOBAL: project; *)
889 [ [ el
= LIST0 entity
; eoi -> el
, None
] ]
891 (* eoi: [[ EOI -> () ]]; *)
893 [ [ "<"; LIDENT
"entity"; LIDENT
"name"; "="; name = LIDENT
;
894 pl
= LIST0
[ x
= LIDENT
-> x
]; ">"; w
= OPT widget
; "</"; LIDENT
"entity";
897 let entity = {en_name
= name; en_params
= pl
; en_ele
= w
} in
899 (* let loc = ((fst loc).Lexing.pos_cnum, (snd loc).Lexing.pos_cnum) in *)
900 ast_of_entity loc entity
902 with Field_error m
->
908 [ [ "<"; tag
= LIDENT
; LIDENT
"name"; "="; (name, nloc
) = ident
;
909 proplist
= LIST0 property
; ">"; children
= LIST0 widget
;
910 (tag_end
, loc_tend
) = tag_end
->
911 if tag
<> tag_end
then
913 (Stream.Error
("</" ^ tag ^
"> expected"));
915 List.filter
(fun (x
, v, vloc
) -> x
<> "expanded" && x
<> "in_interface") proplist
920 {prop_kind
= Zog_misc.property_kind_of_property_name x
;
921 prop_value
= Zog_misc.decode
v;
922 prop_value_loc
= vloc
})
923 (* ((fst vloc).Lexing.pos_cnum, (snd vloc).Lexing.pos_cnum)}) *)
926 (* let nloc = ((fst loc).Lexing.pos_cnum, (snd loc).Lexing.pos_cnum) in *)
927 { name = name; name_loc
= loc;
928 classe
= Zog_misc.class_of_class_name tag
;
935 [ [ "</"; tag
= LIDENT
; ">" -> tag
, loc ] ]
938 [ [ x
= LIDENT
; "="; (v, vloc
) = string -> x
, v, vloc
939 | "function"; "="; (v, vloc
) = string -> "function", v, vloc
]
943 [ [ v = STRING
-> v, loc ] ]
947 [ v = LIDENT
-> v, loc
960 module M
= Camlp4.Register.OCamlSyntaxExtension
(Id
)(Zoggy
)
962 (* let _ = Pcaml.parse_implem := Grammar.Entry.parse project *)