(* * <COPYRIGHT> * Copyright 2006 Gerd Stolpmann * * <GPL> * This file is part of WDialog. * * WDialog is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * WDialog is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with WDialog; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * </> *) (* $Id: wd_init_expr.ml,v 3.2 2006-03-08 16:05:02 stolpmann Exp $ *) open Wd_types open Wd_util open Wd_brexpr open Pxp_types let parse_init_expr enc ev_list : init_expr = let rec parse_value_expr ev_stream = match ev_stream with parser | [< 'E_start_tag("ui:string-value",_,_,_); s_opt = parse_char_data_opt; 'E_end_tag("ui:string-value",_) >] -> let expr = match s_opt with | Some s -> Wd_brexpr.parse_expr_string ~enable_param:false ~enable_brexpr:true enc s | None -> [] in `String_iexpr expr | [< 'E_start_tag("ui:enum-value",_,_,_); items = parse_enum_items; 'E_end_tag("ui:enum-value",_) >] -> `Enum_iexpr items | [< 'E_start_tag("ui:dyn-enum-value",_,_,_); items = parse_dyn_enum_items; 'E_end_tag("ui:dyn-enum-value",_) >] -> `Dyn_enum_iexpr items | [< 'E_start_tag("ui:any-value",_,_,_); 'E_char_data s; 'E_end_tag("ui:any-value",_); >] -> let expr_l = Wd_brexpr.parse_expr_string ~enable_param:false ~enable_brexpr:true enc s in ( match expr_l with | [ (#expr as expr, _) ] -> `Value_iexpr expr | [ (`Expr_oe _, _) ] -> raise(Formal_user_error("The element ui:any-value must not specify an output encoding")) | _ -> raise(Formal_user_error("The element ui:any-value must exactly contain one bracket expression $[...]")) ) | [< 'E_start_tag("ui:matrix-value",_,_,_); head = parse_matrix_head; body = parse_matrix_body head; 'E_end_tag("ui:matrix-value",_); >] -> `Matrix_iexpr(head, Array.of_list body) | [< 'E_start_tag("ui:map-value",atts,_,_); inner_exprs = parse_value_exprs; 'E_end_tag("ui:map-value",_) >] -> let mapping_expr = try List.assoc "mapping" atts with | Not_found -> raise(Formal_user_error("Missing attribute 'mapping' in ui:map-value")) in let mapping_l = Wd_brexpr.parse_expr_string ~enable_param:false ~enable_brexpr:true enc mapping_expr in ( match mapping_l with | [ (#expr as expr, _) ] -> `Map_iexpr (expr, inner_exprs) | [ (`Expr_oe _, _) ] -> raise(Formal_user_error("The attribute 'mapping' of ui:map-value must not specify an output encoding")) | _ -> raise(Formal_user_error("The attribute 'mapping' of ui:map-value must exactly contain one bracket expression $[...]")) ) | [< 'E_start_tag("ui:ds-value",atts,_,_); s_opt = parse_char_data_opt; 'E_end_tag("ui:ds-value",_); >] -> let ds = try List.assoc "ds" atts with | Not_found -> raise(Formal_user_error("Missing attribute 'ds' in ui:ds-value")) in let expr = match s_opt with | Some s -> Wd_brexpr.parse_expr_string ~enable_param:false ~enable_brexpr:true enc s | None -> [] in `Dsrc_iexpr(ds, expr) | [< 'E_start_tag("ui:alist-value",_,_,_); items = parse_alist_items; 'E_end_tag("ui:alist-value",_) >] -> `Alist_iexpr items and parse_char_data_opt ev_stream = match ev_stream with parser | [< 'E_char_data s >] -> Some s | [< >] -> None and parse_enum_items ev_stream = match ev_stream with parser | [< 'E_start_tag("ui:enum-item", atts, _, _); 'E_end_tag("ui:enum-item",_); items = parse_enum_items; >] -> let int_expr = try List.assoc "internal" atts with | Not_found -> raise(Formal_user_error("The attribute 'internal' is required for ui:enum-item")) in let int = Wd_brexpr.parse_expr_string ~enable_param:false ~enable_brexpr:true enc int_expr in int :: items | [< >] -> [] and parse_dyn_enum_items ev_stream = match ev_stream with parser | [< 'E_start_tag("ui:dyn-enum-item", atts, _, _); 'E_end_tag("ui:dyn-enum-item",_); items = parse_dyn_enum_items; >] -> let int_expr = try List.assoc "internal" atts with | Not_found -> raise(Formal_user_error("The attribute 'internal' is required for ui:dyn-enum-item")) in let int = Wd_brexpr.parse_expr_string ~enable_param:false ~enable_brexpr:true enc int_expr in let ext = try Wd_brexpr.parse_expr_string ~enable_param:false ~enable_brexpr:true enc (List.assoc "external" atts) with | Not_found -> int in (int, ext) :: items | [< >] -> [] and parse_alist_items ev_stream = match ev_stream with parser | [< 'E_start_tag("ui:alist-item", atts, _, _); inner_expr = parse_value_expr; 'E_end_tag("ui:alist-item",_); items = parse_alist_items; >] -> let index_expr = try List.assoc "index" atts with | Not_found -> raise(Formal_user_error("The attribute 'index' is required for ui:alist-item")) in let index = Wd_brexpr.parse_expr_string ~enable_param:false ~enable_brexpr:true enc index_expr in (index, inner_expr) :: items | [< >] -> [] and parse_matrix_head ev_stream = let columns = parse_matrix_head_1 ev_stream in let dup_columns = duplicates columns in if dup_columns <> [] then raise(Formal_user_error("Duplicate columns (in ui:matrix-head): " ^ String.concat ", " dup_columns)); Array.of_list columns and parse_matrix_head_1 ev_stream = match ev_stream with parser | [< 'E_start_tag("ui:matrix-head",atts,_,_); 'E_end_tag("ui:matrix-head",_); head = parse_matrix_head_1 >] -> let column = try List.assoc "column" atts with | Not_found -> raise(Formal_user_error("The attribute 'column' is required for ui:matrix-head")) in column :: head | [< >] -> [] and parse_matrix_body head ev_stream = match ev_stream with parser | [< 'E_start_tag("ui:matrix-row",_,_,_); row = parse_matrix_row; 'E_end_tag("ui:matrix-row",_); matrix = parse_matrix_body head >] -> let col_names = List.map fst row in let dup_col_names = duplicates col_names in if dup_col_names <> [] then raise(Formal_user_error("Duplicate columns (in ui:matrix-cell): " ^ String.concat ", " dup_col_names)); let mrow = Array.init (Array.length head) (fun k -> let col = head.(k) in let cell = try List.assoc col row with | Not_found -> raise(Formal_user_error("Missing column in row: " ^ col)) in cell ) in mrow :: matrix | [< >] -> [] and parse_matrix_row ev_stream = match ev_stream with parser | [< 'E_start_tag("ui:matrix-cell", atts, _, _); 'E_char_data s; 'E_end_tag("ui:matrix-cell",_); row = parse_matrix_row; >] -> let expr = Wd_brexpr.parse_expr_string ~enable_param:false ~enable_brexpr:true enc s in let column = try List.assoc "column" atts with | Not_found -> raise(Formal_user_error("The attribute 'column' is required for ui:matrix-cell")) in (column, expr) :: row | [< >] -> [] and parse_value_exprs ev_stream = match ev_stream with parser | [< expr = parse_value_expr; exprs = parse_value_exprs; >] -> expr :: exprs | [< >] -> [] in try ( let ev_stream = Stream.of_list ev_list in match ev_stream with parser | [< expr = parse_value_expr; 'E_end_of_stream >] -> expr ) with | Stream.Failure | Stream.Error "" -> raise(Formal_user_error "Syntax error in dialog initializer") | Stream.Error msg -> raise(Formal_user_error("Syntax error in dialog initializer: " ^ msg)) ;; let eval_init_expr dlg iexpr = let rec eval iexpr = match iexpr with | `String_iexpr sexpr -> String_value(Wd_brexpr_eval.eval_string_expr dlg sexpr) | `Enum_iexpr items -> Enum_value (List.map (fun sexpr -> Wd_brexpr_eval.eval_string_expr dlg sexpr) items) | `Dyn_enum_iexpr items -> Dyn_enum_value (List.map (fun (sexpr1, sexpr2) -> let s1 = Wd_brexpr_eval.eval_string_expr dlg sexpr1 in let s2 = Wd_brexpr_eval.eval_string_expr dlg sexpr2 in (s1,s2) ) items ) | `Alist_iexpr items -> Alist_value (List.map (fun (sexpr, iexpr) -> let s = Wd_brexpr_eval.eval_string_expr dlg sexpr in let v = eval iexpr in ( match v with | Alist_value _ -> raise(Eval_error_noloc("Alists must not contain inner alists")) | _ -> () ); (s, v) ) items ) | `Matrix_iexpr (head, rows) -> Matrix_value (head, Array.map (fun row -> Array.map (fun sexpr -> Wd_brexpr_eval.eval_string_expr dlg sexpr) row) rows) | `Value_iexpr any_expr -> Wd_brexpr_eval.eval_expr dlg any_expr | `Map_iexpr (fun_expr, iexprs) -> let mapping_v = Wd_brexpr_eval.eval_expr dlg fun_expr in let argument_v_l = List.map eval iexprs in let argument_v_a = Array.of_list argument_v_l in let arg_n = List.length argument_v_l in let arg_names = Array.init arg_n (fun k -> "arg_" ^ string_of_int k) in let arg_name_vals = Array.mapi (fun k name -> (name, lazy argument_v_a.(k)) ) arg_names in Wd_brexpr_eval.eval_expr ~local_bindings:( [ "mapping", lazy mapping_v ] @ Array.to_list arg_name_vals ) dlg (`Expr_apply(`Expr_var "mapping", Array.to_list (Array.map (fun n -> `Expr_var n) arg_names))) | `Dsrc_iexpr (provider_name, sexpr) -> let provider = try dlg#application#data_source provider_name with | Not_found -> raise(Eval_error_noloc("Undefined data source: " ^ provider_name)) in let provider_expr = Wd_brexpr_eval.eval_string_expr dlg sexpr in let table = provider # retrieve provider_expr in Table_value table in eval iexpr ;;