diff --git a/src/grew_fs.ml b/src/grew_fs.ml index 19b390d921831b1ce31f754a2683d9380e274294..9b0f9f20a03727f7e02943ecdb4860364f921e0d 100644 --- a/src/grew_fs.ml +++ b/src/grew_fs.ml @@ -432,14 +432,14 @@ module P_fs = struct exception Fail - let match_ ?param p_fs g_fs = + let match_ ?(lexicons=[]) p_fs g_fs = let p_fs_wo_pos = try List.remove_assoc "position" p_fs with Not_found -> p_fs in let rec loop acc = function | [], _ -> acc - (* a feature_name present only in instance -> Skip it *) + (* a feature_name present only in graph -> Skip it *) | ((fn_pat, fv_pat)::t_pat, (fn, _)::t) when fn_pat > fn -> loop acc ((fn_pat, fv_pat)::t_pat, t) (* Two next cases: p_fs requires for the absence of a feature -> OK *) @@ -451,26 +451,25 @@ module P_fs = struct | ((fn_pat, _)::_, (fn, _)::_) when fn_pat < fn -> raise Fail (* Next cases: fn_pat = fn *) - | ((_, {P_feature.cst=cst; P_feature.in_param=in_param})::t_pat, (_, atom)::t) -> - - (* check for the constraint part and fail if needed *) - let () = match cst with - | P_feature.Absent -> raise Fail - | P_feature.Equal fv when not (List_.sort_mem atom fv) -> raise Fail - | P_feature.Different fv when List_.sort_mem atom fv -> raise Fail - | _ -> () in - - (* if constraint part don't fail, look for lexical parameters *) - match (acc, in_param) with - | (_,[]) -> loop acc (t_pat,t) - | (None,_) -> Log.bug "[P_fs.match_] Parametrized constraint in a non-parametrized rule"; exit 2 - | (Some param, [index]) -> - (match Lex_par.select index (string_of_value atom) param with - | [] -> raise Fail - | new_param -> loop (Some new_param) (t_pat,t) - ) - | _ -> Error.bug "[P_fs.match_] several different parameters contraints for the same feature is not implemented" in - loop param (p_fs_wo_pos,g_fs) + | ((_, {P_feature.cst=P_feature.Absent})::_, (_, atom)::t) -> raise Fail + | ((_, {P_feature.cst=P_feature.Equal fv})::_, (_, atom)::t) when not (List_.sort_mem atom fv) -> raise Fail + | ((_, {P_feature.cst=P_feature.Different fv})::_, (_, atom)::t) when List_.sort_mem atom fv -> raise Fail + + | ((_, {P_feature.cst=P_feature.Equal_lex (lex_name,field)})::t_pat, (_, atom)::t) -> + begin + try + let lexicon = List.assoc lex_name acc in + match Lexicon.select field (string_of_value atom) lexicon with + | None -> raise Fail + | Some new_lexicon -> + let new_acc = (lex_name, new_lexicon) :: (List.remove_assoc lex_name acc) in + loop new_acc (t_pat, t) + with + | Not_found -> failwith "TODO" + end + | _ -> acc + + in loop lexicons (p_fs_wo_pos,g_fs) exception Fail_unif let unif fs1 fs2 = diff --git a/src/grew_fs.mli b/src/grew_fs.mli index ecdb2a7ed36f755ac0ac69534687920602302f5a..f146a5798a0045b59734736be939fa7c444aff05 100644 --- a/src/grew_fs.mli +++ b/src/grew_fs.mli @@ -92,7 +92,9 @@ module P_fs: sig If [param] is [None], it returns [None] if matching succeeds and else raise [Fail]. If [param] is [Some p], it returns [Some p'] if matching succeeds and else raise [Fail]. *) - val match_: ?param:Lex_par.t -> t -> G_fs.t -> Lex_par.t option + val match_: + ?lexicons:(string * Grew_types.Lexicon.t) list -> + t -> G_fs.t -> (string * Grew_types.Lexicon.t) list (** [check_position ?parma position pfs] checks wheter [pfs] is compatible with a node at [position]. It returns [true] iff [pfs] has no requirement about position ok if the requirement is satisfied. *) diff --git a/src/grew_node.ml b/src/grew_node.ml index ee7e54c57faa9ba52674490da3170bf29bc4ddd0..fff467a2dddaff2836fc473b38cee6ac5e68c35c 100644 --- a/src/grew_node.ml +++ b/src/grew_node.ml @@ -173,13 +173,14 @@ module P_node = struct | Some l -> Some {t with next = l} | None -> None - let match_ ?param p_node g_node = + + let match_ ?lexicons p_node g_node = (* (match param with None -> printf "<None>" | Some p -> printf "<Some>"; Lex_par.dump p); *) match G_node.get_position g_node with - | G_node.Unordered _ -> None + | G_node.Unordered _ -> raise P_fs.Fail (* TOOO: check this return !! *) | G_node.Ordered p -> - if P_fs.check_position ?param (Some p) p_node.fs - then P_fs.match_ ?param p_node.fs (G_node.get_fs g_node) + if P_fs.check_position (Some p) p_node.fs + then P_fs.match_ ?lexicons p_node.fs (G_node.get_fs g_node) else raise P_fs.Fail let compare_pos t1 t2 = Pervasives.compare t1.loc t2.loc diff --git a/src/grew_node.mli b/src/grew_node.mli index ee51aca942e390daa8c9188ac2995006af284620..59246904ba5e18a60d6d01b9b7ed9b7e1c9425d4 100644 --- a/src/grew_node.mli +++ b/src/grew_node.mli @@ -106,7 +106,9 @@ module P_node: sig val add_edge: P_edge.t -> Pid.t -> t -> t option - val match_: ?param: Lex_par.t -> t -> G_node.t -> Lex_par.t option + val match_: + ?lexicons:(string * Grew_types.Lexicon.t) list -> + t -> G_node.t -> (string * Grew_types.Lexicon.t) list val compare_pos: t -> t -> int end diff --git a/src/grew_rule.ml b/src/grew_rule.ml index 4044ad0bf70176dae982249ce23df22759abea0d..0c438363de9bd7908b764ed7b17abe2ff003f2f5 100644 --- a/src/grew_rule.ml +++ b/src/grew_rule.ml @@ -601,7 +601,7 @@ module Rule = struct n_match: Gid.t Pid_map.t; (* partial fct: pattern nodes |--> graph nodes *) e_match: (string*(Gid.t*Label.t*Gid.t)) list; (* edge matching: edge ident |--> (src,label,tar) *) m_param: Lex_par.t option; - (* l_param: (string * Lexicon.t) list; *) + l_param: (string * Lexicon.t) list; } @@ -624,7 +624,7 @@ module Rule = struct (P_node.get_name pnode, G_node.get_float gnode) :: acc ) n_match [] - let empty_matching param = { n_match = Pid_map.empty; e_match = []; m_param = param;} + let empty_matching lexicons param = { n_match = Pid_map.empty; e_match = []; m_param = param; l_param = lexicons;} let e_comp (e1,_) (e2,_) = compare e1 e2 @@ -687,7 +687,7 @@ module Rule = struct - the ?domain of the pattern P is the disjoint union of ?domain([sub]) and [unmatched_nodes] *) (* ---------------------------------------------------------------------- *) - let init param basic = + let init lexicons param basic = let roots = P_graph.roots basic.graph in let node_list = Pid_map.fold (fun pid _ acc -> pid::acc) basic.graph [] in @@ -700,7 +700,7 @@ module Rule = struct | false, true -> 1 | _ -> 0) node_list in - { sub = empty_matching param; + { sub = empty_matching lexicons param; unmatched_nodes = sorted_node_list; unmatched_edges = []; already_matched_gids = []; @@ -746,8 +746,8 @@ module Rule = struct try let gid = Pid_map.find pid matching.n_match in let gnode = G_graph.find gid graph in - let new_param = P_fs.match_ ?param:matching.m_param fs (G_node.get_fs gnode) in - {matching with m_param = new_param } + let new_param = P_fs.match_ ~lexicons:(matching.l_param) fs (G_node.get_fs gnode) in + {matching with l_param = new_param } with P_fs.Fail -> raise Fail end | Features_eq (pid1, feat_name1, pid2, feat_name2) -> @@ -825,7 +825,28 @@ module Rule = struct if G_node.get_position gnode1 < G_node.get_position gnode2 then matching else raise Fail - | Feature_eq_lex (_, _, _) |Feature_diff_lex (_, _, _) -> failwith ("TODOLEX") + | Feature_eq_lex (pid, feature_name, (lexicon,field)) -> + begin + Printf.printf "### Feature_eq_lex\n%!"; + match get_string_feat pid feature_name with + | None -> raise Fail + | Some v -> + let old_lex = List.assoc lexicon matching.l_param in + match Lexicon.select field v old_lex with + | None -> raise Fail + | Some new_lex -> {matching with l_param = (lexicon, new_lex) :: (List.remove_assoc lexicon matching.l_param) } + end + + | Feature_diff_lex (pid, feature_name, (lexicon,field)) -> + begin + match get_string_feat pid feature_name with + | None -> raise Fail + | Some v -> + let old_lex = List.assoc lexicon matching.l_param in + match Lexicon.unselect field v old_lex with + | None -> raise Fail + | Some new_lex -> {matching with l_param = (lexicon, new_lex) :: (List.remove_assoc lexicon matching.l_param) } + end (* ---------------------------------------------------------------------- *) @@ -904,7 +925,7 @@ module Rule = struct let g_node = try G_graph.find gid graph with Not_found -> Error.bug "[extend_matching_from] cannot find gid in graph" in try - let new_param = P_node.match_ ?param: partial.sub.m_param p_node g_node in + let new_lex_set = P_node.match_ ~lexicons:partial.sub.l_param p_node g_node in (* add all out-edges from pid in pattern *) let new_unmatched_edges = Massoc_pid.fold @@ -916,7 +937,7 @@ module Rule = struct unmatched_nodes = (try List_.rm pid partial.unmatched_nodes with Not_found -> Error.bug "[extend_matching_from] cannot find pid in unmatched_nodes"); unmatched_edges = new_unmatched_edges; already_matched_gids = gid :: partial.already_matched_gids; - sub = {partial.sub with n_match = Pid_map.add pid gid partial.sub.n_match; m_param = new_param}; + sub = {partial.sub with n_match = Pid_map.add pid gid partial.sub.n_match; l_param = new_lex_set}; } in extend_matching ?domain (positive,neg) graph new_partial with P_fs.Fail -> [] @@ -1024,7 +1045,7 @@ module Rule = struct (function | Command.Feat (cnode, feat_name) -> Concat_item.Feat (node_find cnode, feat_name) | Command.String s -> Concat_item.String s - | Command.Lexical_field _ -> failwith "TODOLEX" + | Command.Lexical_field _ -> failwith "TODOLEX1" | Command.Param index -> (match matching.m_param with | None -> Error.bug "Cannot apply a UPDATE_FEAT command without parameter" @@ -1193,7 +1214,7 @@ module Rule = struct | _ -> false (* ---------------------------------------------------------------------- *) - let match_in_graph ?domain ?param (pos, negs) graph = + let match_in_graph ?domain ?(lexicons=[]) ?param (pos, negs) graph = let casted_graph = G_graph.cast ?domain graph in let pos_graph = pos.graph in @@ -1203,7 +1224,7 @@ module Rule = struct ?domain (pos_graph,P_graph.empty) casted_graph - (init param pos) in + (init lexicons param pos) in let filtered_matching_list = List.filter @@ -1232,7 +1253,7 @@ module Rule = struct else List.fold_left (fun acc rule -> - let matching_list = match_in_graph ?domain ~param:(fst rule.param) rule.pattern instance.Instance.graph in + let matching_list = match_in_graph ?domain ~lexicons:rule.lexicons ~param:(fst rule.param) rule.pattern instance.Instance.graph in List.fold_left (fun acc1 matching -> Instance_set.add (apply_rule ?domain instance matching rule) acc1 @@ -1265,7 +1286,7 @@ module Rule = struct ?domain (pos.graph,P_graph.empty) instance.Instance.graph - (init (Some (fst rule.param)) pos) in + (init rule.lexicons (Some (fst rule.param)) pos) in try let (first_matching_where_all_witout_are_fulfilled,_) = List.find @@ -1340,7 +1361,7 @@ module Rule = struct else Error.run "max depth %d reached, last rules applied: …, %s" !max_depth_non_det (List_.rev_to_string (fun x->x) ", " (List_.cut 5 instance.Instance.rules)) else - let matching_list = match_in_graph ?domain ?param:(Some (fst rule.param)) rule.pattern instance.Instance.graph in + let matching_list = match_in_graph ?domain ~lexicons:rule.lexicons ?param:(Some (fst rule.param)) rule.pattern instance.Instance.graph in List.fold_left (fun acc matching -> Instance_set.add (apply_rule ?domain instance matching rule) acc @@ -1363,7 +1384,7 @@ module Rule = struct ?domain (pos.graph,P_graph.empty) instance.Instance.graph - (init (Some (fst rule.param)) pos) in + (init rule.lexicons (Some (fst rule.param)) pos) in try let (first_matching_where_all_witout_are_fulfilled,_) = List.find @@ -1480,7 +1501,15 @@ module Rule = struct (function | Command.Feat (cnode, feat_name) -> Concat_item.Feat (node_find cnode, feat_name) | Command.String s -> Concat_item.String s - | Command.Lexical_field _ -> failwith "TODOLEX" + | Command.Lexical_field (lex_name, field) -> + (try + let lexicon = List.assoc lex_name matching.l_param in + let v = Lexicon.read field lexicon in + Concat_item.String v + with + | Not_found -> Error.run ~loc "UPDATE_FEAT: the lexicon '%s' does not exist" lex_name + | Lexicon.Not_functional_lexicon -> Error.run ~loc "UPDATE_FEAT: the lexicon is not functional" lex_name + ) | Command.Param index -> (match matching.m_param with | None -> Error.bug "Cannot apply a UPDATE_FEAT command without parameter" @@ -1539,7 +1568,7 @@ module Rule = struct ?domain (pos.graph,P_graph.empty) graph - (init (Some (fst rule.param)) pos) in + (init rule.lexicons (Some (fst rule.param)) pos) in try let (first_matching_where_all_witout_are_fulfilled,_) = List.find @@ -1582,7 +1611,7 @@ module Rule = struct ?domain (pos.graph,P_graph.empty) graph - (init (Some (fst rule.param)) pos) in + (init rule.lexicons (Some (fst rule.param)) pos) in try let (first_matching_where_all_witout_are_fulfilled,_) = List.find @@ -1723,7 +1752,7 @@ module Rule = struct (function | Command.Feat (cnode, feat_name) -> Concat_item.Feat (node_find cnode, feat_name) | Command.String s -> Concat_item.String s - | Command.Lexical_field _ -> failwith "TODOLEX" + | Command.Lexical_field _ -> failwith "TODOLEX3" | Command.Param index -> (match matching.m_param with | None -> Error.bug "Cannot apply a UPDATE_FEAT command without parameter" @@ -1856,7 +1885,7 @@ module Rule = struct !max_depth_non_det (List_.rev_to_string (fun x->x) ", " (List_.cut 5 instance.Instance.rules)) else *) - let matching_list = match_in_graph ?domain ?param:(Some (fst rule.param)) rule.pattern graph_with_history.Graph_with_history.graph in + let matching_list = match_in_graph ?domain ~lexicons:rule.lexicons ?param:(Some (fst rule.param)) rule.pattern graph_with_history.Graph_with_history.graph in List.fold_left (fun acc matching -> Graph_with_history_set.add (gwh_apply_rule ?domain graph_with_history matching rule) acc diff --git a/src/grew_rule.mli b/src/grew_rule.mli index db3c0613d0156ed617f93acd62fd749a5df1fa6b..0e9b641a98b5b13fd7742e65bc4625bf0b5d54b6 100644 --- a/src/grew_rule.mli +++ b/src/grew_rule.mli @@ -110,7 +110,7 @@ module Rule : sig val node_matching: pattern -> G_graph.t -> matching -> (string * float) list (** [match_in_graph rule graph] returns the list of matching of the pattern of the rule into the graph *) - val match_in_graph: ?domain:Domain.t -> ?param:Lex_par.t -> pattern -> G_graph.t -> matching list + val match_in_graph: ?domain:Domain.t -> ?lexicons: (string * Lexicon.t) list -> ?param:Lex_par.t -> pattern -> G_graph.t -> matching list (** [match_deco rule matching] builds the decoration of the [graph] illustrating the given [matching] of the [rule] *) (* NB: it can be computed independly from the graph itself! *) diff --git a/src/grew_types.ml b/src/grew_types.ml index 4ffbbe40ca2f72e96091c74f2f569dc167d566cb..0edcaa758b518f3f0632acce5cc369e5bcd9e2d9 100644 --- a/src/grew_types.ml +++ b/src/grew_types.ml @@ -171,6 +171,7 @@ module Lexicon = struct | (x::xs) :: xss -> (x :: List.map List.hd xss) :: transpose (xs :: List.map List.tl xss) let build items = + if items = [] then Error.bug "[Lexicon.build] a lexicon must not be empty"; let tr = transpose items in let sorted_tr = List.sort (fun l1 l2 -> Pervasives.compare (List.hd l1) (List.hd l2)) tr in match transpose sorted_tr with @@ -204,7 +205,21 @@ module Lexicon = struct match List_.index head lex.header with | None -> Error.build "[Lexicon.select] cannot find %s in lexicon" head | Some index -> - { lex with lines = Line_set.filter (fun line -> List.nth line index = value) lex.lines} + let new_set = Line_set.filter (fun line -> List.nth line index = value) lex.lines in + if Line_set.is_empty new_set + then None + else ( Printf.printf "###>>> Lexicon select %d --> %d\n%!" (Line_set.cardinal lex.lines) (Line_set.cardinal new_set); + Some { lex with lines = new_set } + ) + + let unselect head value lex = + match List_.index head lex.header with + | None -> Error.build "[Lexicon.unselect] cannot find %s in lexicon" head + | Some index -> + let new_set = Line_set.filter (fun line -> List.nth line index <> value) lex.lines in + if Line_set.is_empty new_set + then None + else Some { lex with lines = new_set } let projection head lex = match List_.index head lex.header with @@ -215,14 +230,14 @@ module Lexicon = struct exception Not_functional_lexicon let read head lex = match String_set.elements (projection head lex) with - | [] -> None - | [one] -> Some one + | [] -> Error.bug "[Lexicon.read] a lexicon must not be empty" + | [one] -> one | _ -> raise Not_functional_lexicon let read_multi head lex = match String_set.elements (projection head lex) with - | [] -> None - | l -> Some (String.concat "/" l) + | [] -> Error.bug "[Lexicon.read] a lexicon must not be empty" + | l -> String.concat "/" l end (* module Lexicon *) (* ================================================================================ *) diff --git a/src/grew_types.mli b/src/grew_types.mli index 4b5c9755a799a897634ae5afe107db0ddcc4173e..aa5c321997ec6cd7c7fcdb4ee2b97df1b23470e6 100644 --- a/src/grew_types.mli +++ b/src/grew_types.mli @@ -126,23 +126,20 @@ module Lexicon : sig It supposed that the two lexicons define the same columns *) val union: t -> t -> t - (** [select head value] returns the sublexicon with only items where the [head] column is equals to [value] *) - val select: string -> string -> t -> t + (** [select head value] returns the sublexicon with only items where the [head] column is equal to [value] if any, else returns None *) + val select: string -> string -> t -> t option + + (** [unselect head value] returns the sublexicon with only items where the [head] column is different to [value] if any, else returns None *) + val unselect: string -> string -> t -> t option exception Not_functional_lexicon - (** [read head lexicon] returns - * None if [lexicon] is empty; - * Some value if all items have a [head] column equals to [value] - * raise [Not_functional_lexicon] if several values are defined - *) - val read: string -> t -> string option - - (** [read_multi head lexicon] returns - * None if [lexicon] is empty; - * Some "v_1/…/v_k" where v_i are the values of the [head] column - *) - val read_multi: string -> t -> string option + (** [read head lexicon] return [value] if all items have in the [head] column equals to [value] + * raise [Not_functional_lexicon] if several values are defined *) + val read: string -> t -> string + + (** [read_multi head lexicon] returns "v_1/…/v_k" where v_i are the values of the [head] column *) + val read_multi: string -> t -> string end (* module Lexicon *) (* ================================================================================ *)