소스 검색

[netlib] initial property support

Caue Waneck 12 년 전
부모
커밋
f491359074
1개의 변경된 파일113개의 추가작업 그리고 2개의 파일을 삭제
  1. 113 2
      gencs.ml

+ 113 - 2
gencs.ml

@@ -28,6 +28,7 @@ open Gencommon.SourceWriter
 open Type
 open Printf
 open Option
+open ExtString
 
 let is_cs_basic_type t =
   match follow t with
@@ -1351,6 +1352,66 @@ let configure gen =
         (params, String.concat " " params_extends)
   in
 
+	let rec gen_prop w is_static cl is_final (prop,t,get,set) =
+    let is_interface = cl.cl_interface in
+		let fn_is_final = function
+			| None -> true
+			| Some ({ cf_kind = Method mkind } as m) ->
+				(match mkind with | MethInline -> true | _ -> false) || Meta.has Meta.Final m.cf_meta
+			| _ -> assert false
+		in
+		let is_virtual = not (is_final || Meta.has Meta.Final prop.cf_meta || fn_is_final get || fn_is_final set) in
+
+		let fn_is_override = function
+			| Some cf -> List.memq cf cl.cl_overrides
+			| None -> false
+		in
+		let is_override = fn_is_override get || fn_is_override set in
+		let visibility = if is_interface then "" else "public" in
+		let visibility, modifiers = get_fun_modifiers prop.cf_meta visibility [] in
+		let v_n = if is_static then "static " else if is_override && not is_interface then "override " else if is_virtual then "virtual " else "" in
+		print w "%s %s %s %s %s" (visibility) v_n (String.concat " " modifiers) (t_s (run_follow gen t)) (change_field prop.cf_name);
+		let check cf = match cf with
+			| Some ({ cf_overloads = o :: _ } as cf) ->
+					gen.gcon.error "Property functions with more than one overload is currently unsupported" cf.cf_pos;
+					gen.gcon.error "Property functions with more than one overload is currently unsupported" o.cf_pos
+			| _ -> ()
+		in
+		check get;
+		check set;
+
+		begin_block w;
+		(match prop.cf_kind with
+		| Var { v_read = AccCall } when is_interface ->
+			write w "get;";
+		| _ -> match get with
+			| Some { cf_expr = Some e }  ->
+				write w "get ";
+				begin_block w;
+				expr_s w e;
+				end_block w
+			| _ -> ());
+		(match prop.cf_kind with
+		| Var { v_write = AccCall } when is_interface ->
+			write w "set;";
+		| _ -> match set with
+			| Some { cf_expr = Some e }  ->
+				write w "set ";
+				let rec map = function
+					| { eexpr = TReturn (Some e) } ->
+						{ e with
+							eexpr = TBlock [e; { e with eexpr = TReturn None } ];
+						}
+					| e -> Type.map_expr map e
+				in
+				let e = map e in
+				begin_block w;
+				expr_s w e;
+				end_block w
+			| _ -> ());
+		end_block w;
+	in
+
   let rec gen_class_field w ?(is_overload=false) is_static cl is_final cf =
     let is_interface = cl.cl_interface in
     let name, is_new, is_explicit_iface = match cf.cf_name with
@@ -1729,9 +1790,59 @@ let configure gen =
       | Some init ->
         print w "static %s() " (snd cl.cl_path);
         expr_s w (mk_block init));
+
+		(* collect properties *)
+		let partition_props cl cflist =
+			let t = TInst(cl, List.map snd cl.cl_types) in
+			(* first get all vars declared as properties *)
+			let props, nonprops = List.partition (fun v -> match v.cf_kind with
+				| Var { v_read = AccCall } | Var { v_write = AccCall } ->
+					Type.is_extern_field v
+				| _ -> false
+			) cflist in
+			let props = ref (List.map (fun v -> (v.cf_name, ref (v,v.cf_type,None,None))) props) in
+
+			let find_prop name = try
+					List.assoc name !props
+				with | Not_found -> match field_access gen t name with
+					| FClassField (_,_,_,v,_,t,_) when Type.is_extern_field v ->
+						let ret = ref (v,t,None,None) in
+						props := (name, ret) :: !props;
+						ret
+					| _ -> raise Not_found
+			in
+			(* get all functions that are getters/setters *)
+			let nonprops = List.filter (function
+				| cf when String.starts_with cf.cf_name "get_" -> (try
+					(* find the property *)
+					let prop = find_prop (String.sub cf.cf_name 4 (String.length cf.cf_name - 4)) in
+					let v, t, get, set = !prop in
+					assert (get = None);
+					prop := (v,t,Some cf,set);
+					false
+				with | Not_found -> true)
+				| cf when String.starts_with cf.cf_name "set_" -> (try
+					(* find the property *)
+					let prop = find_prop (String.sub cf.cf_name 4 (String.length cf.cf_name - 4)) in
+					let v, t, get, set = !prop in
+					assert (set = None);
+					prop := (v,t,get,Some cf);
+					false
+				with | Not_found -> true)
+				| _ -> true
+			) nonprops in
+			List.map (fun (_,v) -> !v) !props, nonprops
+		in
+
+		let fprops, fnonprops = partition_props cl cl.cl_ordered_fields in
+		let sprops, snonprops = partition_props cl cl.cl_ordered_statics in
     (if is_some cl.cl_constructor then gen_class_field w false cl is_final (get cl.cl_constructor));
-    if not cl.cl_interface then List.iter (gen_class_field w true cl is_final) cl.cl_ordered_statics;
-    List.iter (gen_class_field w false cl is_final) cl.cl_ordered_fields;
+		if not cl.cl_interface then begin
+			List.iter (gen_class_field w true cl is_final) snonprops;
+			List.iter (gen_prop w true cl is_final) sprops
+		end;
+    List.iter (gen_class_field w false cl is_final) fnonprops;
+		List.iter (gen_prop w true cl is_final) fprops;
     check_special_behaviors w cl;
     end_block w;
     if cl.cl_interface && cl.cl_ordered_statics <> [] then begin