Browse Source

added haxe.ds.ImmutableList with ml-like pattern matching support

Nicolas Cannasse 7 years ago
parent
commit
a29bd97e9b
2 changed files with 90 additions and 0 deletions
  1. 48 0
      src/typing/matcher.ml
  2. 42 0
      std/haxe/ds/ImmutableList.hx

+ 48 - 0
src/typing/matcher.ml

@@ -188,6 +188,20 @@ module Pattern = struct
 				ctx.locals <- PMap.add name v ctx.locals;
 				v
 		in
+		let is_list_repr en =
+			Meta.has (Meta.Custom ":listRepr") en.e_meta && List.length en.e_names >= 2
+		in
+		let make_ident en id p =
+			let path = [id] in
+			let path = if snd en.e_path <> snd en.e_module.m_path then snd en.e_path :: path else path in
+			let path = List.rev (fst en.e_module.m_path @ snd en.e_module.m_path :: path) in
+			let rec loop = function
+				| [] -> assert false
+				| [id] -> (EConst (Ident id), p)
+				| f :: fl -> (EField (loop fl, f), p)
+			in
+			loop path
+		in
 		let con_enum en ef p =
 			Display.DeprecationCheck.check_enum pctx.ctx.com en p;
 			Display.DeprecationCheck.check_ef pctx.ctx.com ef p;
@@ -374,6 +388,26 @@ module Pattern = struct
 							make pctx false t2 e
 						) el in
 						PatConstructor(ConArray (List.length patterns),patterns)
+					| TEnum (en,etl) when is_list_repr en ->
+						(* convert array into enum pattern *)
+						let p = snd e in
+						let tl, hd = (match en.e_names with tl :: hd :: _ -> tl, hd | _ -> assert false) in
+						let rec build = function
+							| [] -> make_ident en tl p
+							| e :: el -> (ECall (make_ident en hd (snd e),[e;build el]),snd e)
+						in
+						loop (build el)
+					| TAbstract (a,atl) ->
+						(match follow a.a_this with
+						| TEnum (en,_) when is_list_repr en ->
+							let p = snd e in
+							let tl, hd = (match en.e_names with tl :: hd :: _ -> tl, hd | _ -> assert false) in
+							let rec build = function
+								| [] -> make_ident en tl p
+								| e :: el -> (ECall (make_ident en hd (snd e),[e;build el]),snd e)
+							in
+							loop (build el)
+						| _ -> fail());
 					| _ ->
 						fail()
 				end
@@ -462,6 +496,20 @@ module Pattern = struct
 				restore();
 				let pat = make pctx toplevel e1.etype e2 in
 				PatExtractor(v,e1,pat)
+			| EBinop(OpList,e1,e2) ->
+				(match follow t with
+				| TEnum (en,etl) when is_list_repr en ->
+					(* convert array into enum pattern *)
+					let tl, hd = (match en.e_names with tl :: hd :: _ -> tl, hd | _ -> assert false) in
+					loop (ECall (make_ident en hd (snd e),[e1;e2]),snd e)
+				| TAbstract (a, _) ->
+					(match follow a.a_this with
+					| TEnum (en,_) when is_list_repr en ->
+						let tl, hd = (match en.e_names with tl :: hd :: _ -> tl, hd | _ -> assert false) in
+						loop (ECall (make_ident en hd (snd e),[e1;e2]),snd e)
+					| _ -> fail());
+				| _ ->
+					fail())
 			| EDisplay(e,iscall) ->
 				let pat = loop e in
 				let _ = if iscall then Typer.handle_signature_display ctx e (WithType t)

+ 42 - 0
std/haxe/ds/ImmutableList.hx

@@ -0,0 +1,42 @@
+package haxe.ds;
+
+@:listRepr enum ListRepr<T> {
+	Tl;
+	Hd( v : T, tl : ListRepr<T> );
+}
+
+/**
+	Immutable list
+**/
+abstract ImmutableList<T>(ListRepr<T>) from ListRepr<T> to ListRepr<T> {
+
+	@:op(a :: b) static inline function prepend<T>( v : T, a : ImmutableList<T> ) : ImmutableList<T> {
+		return Hd(v,a);
+	}
+	
+	@:to function toArray() : Array<T> {
+		var a = [];
+		var t = this;
+		while( true ) {
+			switch( t ) {
+			case Tl: break;
+			case Hd(v,tl): t = tl; a.push(v);
+			}
+		}
+		return a;
+	}
+
+	@:from static function fromArray<T>( a : Array<T> ) : ImmutableList<T> {
+		var l = Tl;
+		var i = a.length - 1;
+		while( i >= 0 )
+			l = Hd(a[i--],l);
+		return l;
+	}
+		
+	function toString() {
+		var a = toArray();
+		return Std.string(a);
+	}
+	
+}