Jelajahi Sumber

added Bytes and units tests

Nicolas Cannasse 17 tahun lalu
induk
melakukan
1503faf12f
10 mengubah file dengan 546 tambahan dan 7 penghapusan
  1. 5 0
      doc/CHANGES.txt
  2. 210 0
      std/Bytes.hx
  3. 1 0
      std/flash/Boot.hx
  4. 1 0
      std/js/Boot.hx
  5. 78 0
      tests/unit/Test.hx
  6. 94 0
      tests/unit/TestBytes.hx
  7. 96 0
      tests/unit/unit.html
  8. 27 0
      tests/unit/unit.hxml
  9. 10 0
      tests/unit/unit.hxp
  10. 24 7
      typer.ml

+ 5 - 0
doc/CHANGES.txt

@@ -14,6 +14,11 @@ TODO inlining : substitute class+function type parameters in order to have fully
 	added __charCodeAt for very fast string operations on Flash9
 	bugfix with inlined local variables
 	upgraded flash9 api to flex3/player 9.0.115
+	override is now mandatory, no more --override
+	dynamic is now a keyword
+	f9dynamic is now dynamic and is mandatory on all platforms
+	public/private/dynamic are inherited by default when overriding a method
+	added Bytes api
 
 2008-04-05: 1.19
 	fixed flash9 Array.toString

+ 210 - 0
std/Bytes.hx

@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2005-2008, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+class Bytes {
+
+	public var length(default,null) : Int;
+	#if neko
+	var b : Void; // neko-string
+	#else flash9
+	var b : flash.utils.ByteArray;
+	#else true
+	var b : Array<Int>;
+	#end
+
+	function new(length,b) {
+		this.length = length;
+		this.b = b;
+	}
+
+	public inline function get( pos : Int ) : Int {
+		#if neko
+		return untyped __dollar__sget(b,pos);
+		#else flash9
+		return b[pos];
+		#else true
+		return b[pos];
+		#end
+	}
+
+	public inline function set( pos : Int, v : Int ) : Void {
+		#if neko
+		untyped __dollar__sset(b,pos,v);
+		#else flash9
+		b[pos] = v;
+		#else true
+		b[pos] = v;
+		#end
+	}
+
+	public function blit( pos : Int, src : Bytes, srcpos : Int, len : Int ) : Void {
+		#if !neko
+		if( pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length ) throw "Outside bounds";
+		#end
+		#if neko
+		try untyped __dollar__sblit(b,pos,src.b,srcpos,len) catch( e : Dynamic ) throw "Outside bounds";
+		#else flash9
+		b.position = pos;
+		b.writeBytes(src.b,srcpos,len);
+		#else true
+		var b1 = b;
+		var b2 = src.b;
+		if( b1 == b2 && pos > srcpos ) {
+			var i = len;
+			while( i > 0 ) {
+				i--;
+				b1[i + pos] = b2[i + srcpos];
+			}
+			return;
+		}
+		for( i in 0...len )
+			b1[i+pos] = b2[i+srcpos];
+		#end
+	}
+
+	public function compare( other : Bytes ) : Int {
+		#if neko
+		return untyped __dollar__compare(b,other.b);
+		#else flash9
+		var len = (length < other.length) ? length : other.length;
+		var b1 = b;
+		var b2 = other.b;
+		b1.position = 0;
+		b2.position = 0;
+		for( i in 0...len>>2 )
+			if( b1.readUnsignedInt() != b2.readUnsignedInt() ) {
+				b1.position -= 4;
+				b2.position -= 4;
+				return b1.readUnsignedInt() - b2.readUnsignedInt();
+			}
+		for( i in 0...len & 3 )
+			if( b1.readUnsignedByte() != b2.readUnsignedByte() )
+				return b1[b1.position-1] - b2[b2.position-1];
+		return length - other.length;
+		#else true
+		var b1 = b;
+		var b2 = other.b;
+		var len = (length < other.length) ? length : other.length;
+		for( i in 0...len )
+			if( b1[i] != b2[i] )
+				return b1[i] - b2[i];
+		return length - other.length;
+		#end
+	}
+
+	public function readString( pos : Int, len : Int ) : String {
+		#if !neko
+		if( pos < 0 || len < 0 || pos + len > length ) throw "Outside bounds";
+		#end
+		#if neko
+		return try new String(untyped __dollar__ssub(b,pos,len)) catch( e : Dynamic ) throw "Outside bounds";
+		#else flash9
+		b.position = pos;
+		return b.readUTFBytes(len);
+		#else true
+		var s = "";
+		var b = b;
+		var fcc = String.fromCharCode;
+		var i = pos;
+		var max = pos+len;
+		// utf8-encode
+		while( i < max ) {
+			var c = b[i++];
+			if( c < 0x7F )
+				s += fcc(c);
+			else if( c < 0xE0 )
+				s += fcc( ((c & 0x3F) << 6) | (b[i++] & 0x7F) );
+			else if( c < 0xF0 ) {
+				var c2 = b[i++];
+				s += fcc( ((c & 0x1F) << 12) | ((c2 & 0x7F) << 6) | (b[i++] & 0x7F) );
+			} else {
+				var c2 = b[i++];
+				var c3 = b[i++];
+				s += fcc( ((c & 0x0F) << 18) | ((c2 & 0x7F) << 12) | ((c3 << 6) & 0x7F) | (b[i++] & 0x7F) );
+			}
+		}
+		return s;
+		#end
+	}
+
+	public function toString() : String {
+		#if neko
+		return new String(untyped __dollar__ssub(b,0,length));
+		#else flash9
+		b.position = 0;
+		return b.readUTFBytes(length);
+		#else true
+		return readString(0,length);
+		#end
+	}
+
+	public static function alloc( length : Int ) : Bytes {
+		#if neko
+		return new Bytes(length,untyped __dollar__smake(length));
+		#else flash9
+		var b = new flash.utils.ByteArray();
+		b.length = length;
+		return new Bytes(length,b);
+		#else true
+		var a = new Array();
+		for( i in 0...length )
+			a.push(0);
+		return new Bytes(length,a);
+		#end
+	}
+
+	public static function ofString( s : String ) : Bytes {
+		#if neko
+		return new Bytes(s.length,untyped __dollar__ssub(s.__s,0,s.length));
+		#else flash9
+		var b = new flash.utils.ByteArray();
+		b.writeUTFBytes(s);
+		return new Bytes(b.length,b);
+		#else true
+		var a = new Array();
+		// utf8-decode
+		for( i in 0...s.length ) {
+			var c : Int = untyped s.cca(i);
+			if( c < 0x7F )
+				a.push(c);
+			else if( c < 0x7FF ) {
+				a.push( 0xC0 | (c >> 6) );
+				a.push( 0x80 | (c & 63) );
+			} else if( c <= 0xFFFF ) {
+				a.push( 0xE0 | (c >> 12) );
+				a.push( 0x80 | ((c >> 6) & 63) );
+				a.push( 0x80 | (c & 63) );
+			} else {
+				a.push( 0xF0 | (c >> 18) );
+				a.push( 0x80 | ((c >> 12) & 63) );
+				a.push( 0x80 | ((c >> 6) & 63) );
+				a.push( 0x80 | (c & 63) );
+			}
+		}
+		return new Bytes(a.length,a);
+		#end
+	}
+
+}

+ 1 - 0
std/flash/Boot.hx

@@ -260,6 +260,7 @@ class Boot {
 			String.prototype[__unprotect__("__class__")] = String;
 			String[__unprotect__("__name__")] = ["String"];
 			var cca = String.prototype["charCodeAt"];
+			String.prototype["cca"] = cca;
 			String.prototype["charCodeAt"] = function(i) {
 				var x = cca["call"](this,i);
 				if( x <= 0 ) // fast NaN

+ 1 - 0
std/js/Boot.hx

@@ -228,6 +228,7 @@ class Boot {
 			Array.prototype.__class__ = Array;
 			Array.__name__ = ["Array"];
 			var cca = String.prototype.charCodeAt;
+			String.prototype.cca = cca;
 			String.prototype.charCodeAt = function(i) {
 				var x = cca.call(this,i);
 				if( isNaN(x) )

+ 78 - 0
tests/unit/Test.hx

@@ -0,0 +1,78 @@
+package unit;
+
+class Test {
+
+	public function new() {
+	}
+
+	function eq<T>( v : T, v2 : T, ?pos : haxe.PosInfos ) {
+		if( v != v2 ) report(v+" != "+v2,pos);
+	}
+
+	function exc( f : Void -> Void, ?pos : haxe.PosInfos ) {
+		try {
+			f();
+			report("No exception occured",pos);
+		} catch( e : Dynamic ) {
+		}
+	}
+
+	function unspec( f : Void -> Void, ?pos : haxe.PosInfos ) {
+		try {
+			f();
+		} catch( e : Dynamic ) {
+		}
+	}
+
+	function allow<T>( v : T, values : Array<T>, ?pos : haxe.PosInfos ) {
+		for( v2 in values )
+			if( v == v2 )
+				return;
+		report(v+" not in "+Std.string(values),pos);
+	}
+
+	function infos( m : String ) {
+		reportInfos = m;
+	}
+
+	static var reportInfos = null;
+	static var reportCount = 0;
+
+	static function report( msg : String, pos : haxe.PosInfos ) {
+		if( reportInfos != null ) {
+			msg += " ("+reportInfos+")";
+			reportInfos = null;
+		}
+		haxe.Log.trace(msg,pos);
+		reportCount++;
+		if( reportCount > 10 ) throw "Too many errors";
+	}
+
+	static function main() {
+		#if neko
+		if( neko.Web.isModNeko ) neko.Lib.print("<pre>");
+		#end
+		var classes = [
+			new TestBytes(),
+		];
+		var current = null;
+		try {
+			for( inst in classes ) {
+				current = Type.getClass(inst);
+				for( f in Type.getInstanceFields(current) )
+					if( f.substr(0,4) == "test" )
+						Reflect.callMethod(inst,Reflect.field(inst,f),[]);
+			}
+			report("DONE",here);
+		} catch( e : Dynamic ) {
+			reportInfos = null;
+			var msg = "???";
+			var stack = haxe.Stack.toString(haxe.Stack.exceptionStack());
+			try msg = Std.string(e) catch( e : Dynamic ) {};
+			reportCount = 0;
+			report("ABORTED : "+msg+" in "+Type.getClassName(current),here);
+			trace("STACK :\n"+stack);
+		}
+	}
+
+}

+ 94 - 0
tests/unit/TestBytes.hx

@@ -0,0 +1,94 @@
+package unit;
+
+class TestBytes extends Test {
+
+	function test() {
+		var b = Bytes.alloc(10);
+		eq(b.length,10);
+		// get-set
+		for( i in 0...10 )
+			eq(b.get(i),0);
+		unspec(function() b.get(-1));
+		unspec(function() b.get(11));
+		b.set(1,20);
+		eq(b.get(1),20);
+		unspec(function() b.set(-1,20));
+		unspec(function() b.set(11,20));
+		unspec(function() b.set(0,1000));
+		// ofString
+		var b2 = Bytes.ofString("ABCD");
+		eq(b2.length,4);
+		eq(b2.get(0),"A".charCodeAt(0));
+		eq(b2.get(1),"B".charCodeAt(0));
+		eq(b2.get(2),"C".charCodeAt(0));
+		eq(b2.get(3),"D".charCodeAt(0));
+		var b3 = Bytes.ofString("é");
+		eq(b3.length,2);
+		eq(b3.get(0),0xC3);
+		eq(b3.get(1),0xA9);
+		// blit
+		b.blit(3,b2,1,3);
+		eq(b.get(2),0);
+		eq(b.get(3),"B".charCodeAt(0));
+		eq(b.get(4),"C".charCodeAt(0));
+		eq(b.get(5),"D".charCodeAt(0));
+		eq(b.get(6),0);
+		exc(function() b.blit(-1,b2,1,3));
+		exc(function() b.blit(0,b2,2,3));
+		exc(function() b.blit(9,b2,1,3));
+		exc(function() b.blit(0,b2,-1,3));
+		exc(function() b.blit(0,b2,1,-1));
+		exc(function() b.blit(0,b2,1,20));
+		// forward
+		b.blit(4,b,3,3);
+		eq(b.get(2),0);
+		eq(b.get(3),"B".charCodeAt(0));
+		eq(b.get(4),"B".charCodeAt(0));
+		eq(b.get(5),"C".charCodeAt(0));
+		eq(b.get(6),"D".charCodeAt(0));
+		eq(b.get(7),0);
+		// backward
+		b.blit(3,b,5,3);
+		eq(b.get(2),0);
+		eq(b.get(3),"C".charCodeAt(0));
+		eq(b.get(4),"D".charCodeAt(0));
+		eq(b.get(5),0);
+		eq(b.get(6),"D".charCodeAt(0));
+		eq(b.get(7),0);
+		// readString
+		var bs = Bytes.ofString("One é accent");
+		bs.set(3,0); // cut betwen "One" and "é"
+		eq(bs.readString(0,3),"One");
+		eq(bs.readString(4,bs.length-4),"é accent");
+		eq(bs.readString(4,2),"é");
+		exc(function() bs.readString(-1,1));
+		exc(function() bs.readString(1,20));
+		unspec(function() bs.readString(4,1)); // might not allow to cut UTF8 char
+		unspec(function() bs.readString(1,5)); // the handling of \0 might vary
+		/**
+		 	HANDLING of 0x00 in string :
+				Flash8 : ignore
+				Flash9 : cut string
+				JS/FFOX, JS/IE7, Neko : ok (\0 displayed as ? on Firefox, string cut on IE7)
+				JS/IE6 : todo
+				JS/Safari : todo
+				JS/Opera : todo
+		**/
+		// toString
+		eq(b2.toString(),"ABCD");
+		// compare
+		var strings = ["ABCD","ABDC","ABCDE","ABC","BC","AAAAAAAAA",
+			#if !flash8 "" #end // there is an error with empty string comparison in Flash8
+		];
+		for( s1 in strings )
+			for( s2 in strings ) {
+				var c = Bytes.ofString(s1).compare(Bytes.ofString(s2));
+				infos("compare "+s1+" and "+s2);
+				eq( c < 0, s1 < s2 );
+				eq( c > 0, s1 > s2 );
+				eq( c == 0, s1 == s2 );
+			}
+		infos(null);
+	}
+
+}

+ 96 - 0
tests/unit/unit.html

@@ -0,0 +1,96 @@
+<html>
+
+<head>
+	<title>haXe</title>
+	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
+	<script type="text/javascript" src="unit.js"></script>
+</head>
+
+<body bgcolor="#dddddd" onLoad="setTimeout('unit.Test.main()',100)">
+
+<table>
+<tr>
+<td>
+
+<p>JS :</p>
+
+<div id="haxe:trace" style="{ background-color : white; width : 390px; padding : 5px; }">
+</div>
+
+</td>
+<td>
+
+<p>Neko :</p>
+
+<iframe src="http://dev.unit-tests/unit.n" style="{ border : none; background-color : white; width : 400px; }">
+</iframe>
+
+</td>
+</tr>
+
+<tr>
+<td>
+
+<p>Flash 8 :</p>
+
+<object	classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
+        width="400"
+	height="300"
+	id="haxe"
+	align="middle">
+<param name="movie" value="unit8.swf"/>
+<param name="allowScriptAccess" value="always" />
+<param name="quality" value="high" />
+<param name="scale" value="noscale" />
+<param name="salign" value="lt" />
+<param name="bgcolor" value="#ffffff"/>
+<embed src="unit8.swf"
+       bgcolor="#ffffff"
+       width="400"
+       height="300"
+       name="haxe"
+       quality="high"
+       align="middle"
+       allowScriptAccess="always"
+       type="application/x-shockwave-flash"
+       pluginspage="http://www.macromedia.com/go/getflashplayer"
+/>
+</object>
+
+</td>
+<td>
+
+<p>
+Flash 9 :
+</p>
+
+<object	classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
+        width="400"
+	height="300"
+	id="haxe"
+	align="middle">
+<param name="movie" value="unit9.swf"/>
+<param name="allowScriptAccess" value="always" />
+<param name="quality" value="high" />
+<param name="scale" value="noscale" />
+<param name="salign" value="lt" />
+<param name="bgcolor" value="#ffffff"/>
+<embed src="unit9.swf"
+       bgcolor="#ffffff"
+       width="400"
+       height="300"
+       name="haxe"
+       quality="high"
+       align="middle"
+       allowScriptAccess="always"
+       type="application/x-shockwave-flash"
+       pluginspage="http://www.macromedia.com/go/getflashplayer"
+/>
+</object>
+
+</td>
+</tr>
+</table>
+
+</body>
+</html>

+ 27 - 0
tests/unit/unit.hxml

@@ -0,0 +1,27 @@
+# Flash
+-swf unit8.swf
+-main unit.Test
+-debug
+-cp ..
+
+--next
+# Flash9
+-swf unit9.swf
+-swf-version 9
+-main unit.Test
+-debug
+-cp ..
+
+--next
+# JS
+-js unit.js
+unit.Test
+-debug
+-cp ..
+
+--next
+# Neko
+-neko unit.n
+-main unit.Test
+-debug
+-cp ..

+ 10 - 0
tests/unit/unit.hxp

@@ -0,0 +1,10 @@
+<haxe selected="0">
+  <output name="Flash" mode="swf" out="unit8.swf" class="unit.Test" lib="" cmd="unit.html" main="True" debug="True">-cp ..</output>
+  <output name="Flash9" mode="swf9" out="unit9.swf" class="unit.Test" lib="" cmd="" main="True" debug="True">-cp ..</output>
+  <output name="JS" mode="js" out="unit.js" class="unit.Test" lib="" cmd="" main="False" debug="True">-cp ..</output>
+  <output name="Neko" mode="neko" out="unit.n" class="unit.Test" lib="" cmd="" main="True" debug="True">-cp ..</output>
+  <files path="/">
+    <file path="Test.hx" />
+    <file path="TestBytes.hx" />
+  </files>
+</haxe>

+ 24 - 7
typer.ml

@@ -2615,8 +2615,23 @@ let init_class ctx c p herits fields =
 		| Some (c,_) -> extends_public c
 	in
 	let extends_public = extends_public c in
-	let is_public access =
-		if c.cl_extern || c.cl_interface || extends_public then not (List.mem APrivate access) else List.mem APublic access
+	let is_public access parent =
+		if List.mem APrivate access then
+			false
+		else if List.mem APublic access then
+			true
+		else match parent with
+			| Some { cf_public = p } -> p
+			| _ -> c.cl_extern || c.cl_interface || extends_public
+	in
+	let rec get_parent c name = 
+		match c.cl_super with
+		| None -> None
+		| Some (csup,_) ->
+			try
+				Some (PMap.find name csup.cl_fields)
+			with
+				Not_found -> get_parent csup name
 	in
 	let type_opt ?opt ctx p t =
 		match t with
@@ -2657,7 +2672,7 @@ let init_class ctx c p herits fields =
 				cf_get = if inline then InlineAccess else NormalAccess;
 				cf_set = if inline then NeverAccess else NormalAccess;
 				cf_expr = None;
-				cf_public = is_public access;
+				cf_public = is_public access None;
 				cf_params = [];
 			} in
 			let delay = (match e with
@@ -2683,11 +2698,13 @@ let init_class ctx c p herits fields =
 			) params in
 			let stat = List.mem AStatic access in
 			let inline = List.mem AInline access in
+			let parent = (if not stat then get_parent c name else None) in
+			let dynamic = List.mem ADynamic access || (match parent with Some { cf_set = NormalAccess } -> true | _ -> false) in
 			let ctx = { ctx with
 				curclass = c;
 				curmethod = name;
 				tthis = tthis;
-				type_params = if stat then params  else params @ ctx.type_params;
+				type_params = if stat then params else params @ ctx.type_params;
 			} in
 			let ret = type_opt ctx p f.f_type in
 			let args = List.map (fun (name,opt,t) -> name , opt, type_opt ~opt ctx p t) f.f_args in
@@ -2704,9 +2721,9 @@ let init_class ctx c p herits fields =
 				cf_doc = doc;
 				cf_type = t;
 				cf_get = if inline then InlineAccess else NormalAccess;
-				cf_set = (if not (List.mem ADynamic access) then MethodCantAccess else if inline then NeverAccess else NormalAccess);
+				cf_set = (if inline then NeverAccess else if dynamic then NormalAccess else MethodCantAccess);
 				cf_expr = None;
-				cf_public = is_public access;
+				cf_public = is_public access parent;
 				cf_params = params;
 			} in
 			let r = exc_protect (fun r ->
@@ -2772,7 +2789,7 @@ let init_class ctx c p herits fields =
 				cf_set = set;
 				cf_expr = None;
 				cf_type = ret;
-				cf_public = is_public access;
+				cf_public = is_public access None;
 				cf_params = [];
 			} in
 			access, false, cf, (fun() -> (!check_get)(); (!check_set)())