Nicolas Cannasse 19 ani în urmă
părinte
comite
fb74613c9d
1 a modificat fișierele cu 360 adăugiri și 0 ștergeri
  1. 360 0
      std/tools/JsProxy.hx

+ 360 - 0
std/tools/JsProxy.hx

@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2005, 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.
+ */
+package tools;
+
+interface JsResultEvent {
+	var onResult : Dynamic -> Void;
+}
+
+enum JsResult {
+	value( d : Dynamic );
+	delayed( r : JsResultEvent );
+}
+
+class Unserializer {
+
+	var buf : String;
+	var pos : Int;
+	var length : Int;
+	var cache : Array<Dynamic>;
+
+	public function new( buf : String ) {
+		this.buf = buf;
+		length = buf.length;
+		pos = 0;
+		cache = new Array();
+	}
+
+	function readDigits() {
+		var k = 0;
+		var s = false;
+		while( true ) {
+			var c = buf.charCodeAt(pos) - 48;
+			if( c == -3 ) {
+				s = true;
+				pos++;
+				continue;
+			}
+			if( c < 0 || c >= 10 )
+				break;
+			k = k * 10 + c;
+			pos++;
+		}
+		if( s )
+			k *= -1;
+		return k;
+	}
+
+	public function unserialize() : Dynamic {
+		switch( buf.charCodeAt(pos++) ) {
+		case 110: // n
+			return null;
+		case 116: // t
+			return true;
+		case 102: // f
+			return false;
+		case 122: // z
+			return 0;
+		case 105: // i
+			return readDigits();
+		case 100: // d
+			var p1 = pos;
+			while( true ) {
+				var c = buf.charCodeAt(pos);
+				// + - . , 0-9
+				if( (c >= 43 && c < 58) || c == 101 /*e*/ || c == 69 /*E*/ )
+					pos++;
+				else
+					break;
+			}
+			var s = buf.substr(p1,pos-p1);
+			var f = Std.parseFloat(s);
+			if( f == null )
+				throw ("Invalid float "+s);
+			return f;
+		case 107: // k
+			return Std.nan;
+		case 109: // m
+			return -Std.infinity;
+		case 112: // p
+			return Std.infinity;
+		case 115: // s
+			var len = readDigits();
+			if( buf.charAt(pos++) == ":" ) {
+				if( length - pos < len )
+					throw "Invalid string length";
+				var s = buf.substr(pos,len);
+				pos += len;
+				cache.push(s);
+				return s;
+			}
+		case 97: // a
+			var a = new Array<Dynamic>();
+			cache.push(a);
+			while( true ) {
+				if( pos >= length )
+					throw "Invalid array";
+				var c = buf.charCodeAt(pos);
+				if( c == 104 ) /*h*/
+					break;
+				if( c == 117 ) { /*u*/
+					var n = readDigits();
+					if( n <= 0 )
+						throw "Invalid array nulls";
+					a[a.length+n-1] = null;
+				} else
+					a.push(unserialize());
+			}
+			pos++;
+			return a;
+		case 111: // o
+			var o = Reflect.empty();
+			cache.push(o);
+			while( true ) {
+				if( pos >= length )
+					throw "Invalid object";
+				if( buf.charCodeAt(pos) == 103 ) /*g*/
+					break;
+				var k = unserialize();
+				if( !Std.is(k,String) )
+					throw "Invalid object key";
+				var v = unserialize();
+				Reflect.setField(o,k,v);
+			}
+			pos++;
+			return o;
+		case 114: // r
+			var n = readDigits();
+			if( n < 0 || n >= cache.length )
+				throw "Invalid reference";
+			return cache[n];
+		default:
+		}
+		pos--;
+		throw ("Invalid char "+buf.charAt(pos)+" at position "+pos);
+	}
+
+}
+
+class Serializer {
+
+	var buf : StringBuf;
+	var cache : Array<Dynamic>;
+
+	public function new() {
+		buf = new StringBuf();
+		cache = new Array();
+	}
+
+	public function toString() {
+		return buf.toString();
+	}
+
+	/* prefixes :
+		n : null
+		t : true
+		f : false
+		i : Int
+		z : zero
+		d : Float
+		e : reserved (float exp)
+		k : NaN
+		m : -Inf
+		p : +Inf
+		s : string
+		a : array
+		u : array nulls
+		h : array end
+		o : object
+		g : object end
+		r : reference
+	*/
+
+	function serializeString( s : String ) {
+		if( serializeRef(s) )
+			return;
+		buf.add("s");
+		buf.add(s.length);
+		buf.add(":");
+		buf.add(s);
+	}
+
+	function serializeRef(v) {
+		for( i in 0...cache.length ) {
+			if( cache[i] == v ) {
+				buf.add("r");
+				buf.add(i);
+				return true;
+			}
+		}
+		cache.push(v);
+		return false;
+	}
+
+	public function serialize( v : Dynamic ) {
+		if( v == null ) {
+			buf.add("n");
+			return;
+		}
+		if( Std.is(v,Int) ) {
+			if( v == 0 ) {
+				buf.add("z");
+				return;
+			}
+			buf.add("i");
+			buf.add(Std.string(v));
+			return;
+		}
+		if( Std.is(v,Float) ) {
+			if( Std.isNaN(v) )
+				buf.add("k");
+			else if( !Std.isFinite(v) )
+				buf.add(if( v < 0 ) "m" else "p");
+			else {
+				buf.add("d");
+				buf.add(Std.string(v));
+			}
+			return;
+		}
+		if( Std.is(v,String) ) {
+			serializeString(v);
+			return;
+		}
+		if( Std.is(v,Array) ) {
+			if( serializeRef(v) )
+				return;
+			var ucount = 0;
+			buf.add("a");
+			for( i in 0...v.length ) {
+				if( v[i] == null )
+					ucount++;
+				else {
+					if( ucount > 0 ) {
+						if( ucount == 1 )
+							buf.add("n");
+						else {
+							buf.add("u");
+							buf.add(ucount);
+						}
+						ucount = 0;
+					}
+					serialize(v[i]);
+				}
+			}
+			if( ucount > 0 ) {
+				buf.add("u");
+				buf.add(ucount);
+			}
+			buf.add("h");
+			return;
+		}
+		if( v == true ) {
+			buf.add("t");
+			return;
+		}
+		if( v == false ) {
+			buf.add("f");
+			return;
+		}
+		if( serializeRef(v) )
+			return;
+		if( Reflect.isFunction(v) )
+			throw "Cannot serialize function";
+
+		buf.add("o");
+		var fl = Reflect.fields(v);
+		for( f in fl ) {
+			serializeString(f);
+			serialize(Reflect.field(v,f));
+		}
+		buf.add("g");
+	}
+
+}
+
+class JsProxy implements Dynamic<JsProxy> {
+
+	var path : Array<String>;
+
+	public function new() {
+		path = new Array();
+	}
+
+	public function call( args : Array<String> ) : JsResult {
+		var s = new Serializer();
+		s.serialize(path);
+		s.serialize(args);
+		var data = s.toString();
+		var onResult = null;
+		var v : String;
+		#if flash8
+		untyped flash.external.ExternalInterface._initJS();
+		var code = data.split("\\").join("\\\\").split("\n").join("\\n").split("\r").join("\\r").split("\"").join("\\\"");
+		v = untyped flash.external.ExternalInterface._evalJS("JsProxy.__incoming(\""+code+"\")");
+		#else js
+		throw "Unimplemented";
+		#else error
+		#end
+		if( onResult != null )
+			return delayed(onResult);
+		var exc = (v.charAt(0) == "x");
+		var u = new Unserializer(if( exc ) v.substr(1,v.length-1) else v);
+		var v = u.unserialize();
+		if( exc )
+			throw v;
+		return value(v);
+	}
+
+	function __resolve(field) {
+		var s = new JsProxy();
+		s.path = path.copy();
+		s.path.push(field);
+		return s;
+	}
+
+#if js
+	static function __incoming( code : String ) : String {
+		var s = new Unserializer(code);
+		var p = s.unserialize();
+		var args = s.unserialize();
+		try {
+			var m : String = p.pop();
+			var opath = p.join(".");
+			var o = js.Lib.eval(opath);
+			var f = Reflect.field(o,m);
+			if( !Reflect.isFunction(f) )
+				throw ("No such method "+opath+"."+m);
+			var s = new Serializer();
+			s.serialize(Reflect.callMethod(o,f,args));
+			return s.toString();
+		} catch( e : Dynamic ) {
+			var s = new Serializer();
+			s.serialize(e);
+			return "x"+s.toString();
+		}
+	}
+#end
+
+}