-
-
Save sonygod/5412347 to your computer and use it in GitHub Desktop.
| package ; | |
| import haxe.ds.ObjectMap; | |
| import haxe.ds.StringMap; | |
| import haxe.Timer; | |
| import haxe.remoting.ExternalConnection; | |
| import tink.lang.Cls; | |
| import Format; | |
| /** | |
| * ... | |
| * @author sonygod | |
| */ | |
| class FlashMain { | |
| public function foo(x, y) { trace("outsidecall" + x + y); } | |
| static var js:ExternalConnection = null; | |
| static var hello; | |
| public static var onData: Dynamic; | |
| public static function main() { | |
| var ctx = new haxe.remoting.Context(); | |
| ctx.addObject("FlashMain", FlashMain); | |
| js = haxe.remoting.ExternalConnection.jsConnect("default", ctx); | |
| var arr:Array<Int> = [1, 2]; | |
| var arr2=arr.slice(0, arr.length - 1); | |
| hello = new Forwarder(js); | |
| hello.sayHello("hi", "god", onCalljs); | |
| } | |
| public static function onCalljs(err, data) { | |
| trace("回来了,靠"+err+data); | |
| } | |
| public static function __onData(args: Array<Dynamic>) { | |
| //trace(args.toString() + "" + Timer.stamp() * 1000); | |
| var recall = args.pop(); | |
| trace(args.toString() + "" + Timer.stamp() * 1000); | |
| var xxx:StringMap<CallBackObjWithFun> = js.getcallBackList(); | |
| var f :CallBackObjWithFun= xxx.get(recall.id + recall.name); | |
| trace(f.id+f.name+f.callBack); | |
| Reflect.callMethod(FlashMain, f.callBack, args); | |
| } | |
| private static function __init__() : Void { | |
| onData = Reflect.makeVarArgs(__onData); | |
| } | |
| } | |
| class Forwarder implements Cls { | |
| var fields:Hash<Dynamic> = new Hash<Dynamic>(); | |
| public var recallFuns:ObjectMap<Caller ,Dynamic>=new ObjectMap<Caller ,Dynamic>(); | |
| @:forward(!multiply) var target:ExternalConnection; | |
| @:forward function fwd2(hello:HelloService) { | |
| get: fields.get($name), | |
| set: fields.set($name, param), | |
| call:target.resolve("main").resolve("onData").call($argsRemoting) | |
| } | |
| public function new(target) { | |
| this.target = target; | |
| } | |
| } | |
| typedef Caller = { | |
| id:String, | |
| name:String | |
| } | |
package tink.lang.macros;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
import tink.macro.build.Member;
import tink.macro.build.MemberTransformer;
using tink.macro.tools.MacroTools;
using StringTools;
using Lambda;
using tink.core.types.Outcome;
typedef ClassFieldFilter = ClassField->Bool;
typedef ForwardRules = { call:Null, get:Null, set:Null };
class Forward {
static inline var TAG = ":forward";
static public function process(ctx:ClassBuildContext) {
new Forward(ctx.has, ctx.add, ctx.cls.isInterface).processMembers(ctx.members);
}
var hasField:String->Bool;
var addField:Member->?Bool->Member;
var ownerIsInterface:Bool;
function new(hasField, addField, ownerIsInterface) {
this.hasField = hasField;
this.addField = addField;
this.ownerIsInterface = ownerIsInterface;
}
function processMembers(members:Array) {
for (member in members)
switch (member.extractMeta(TAG)) {
case Success(tag):
switch (member.kind) {
case FVar(t, ):
forwardTo(member, t, tag.pos, tag.params);
case FProp(, _, t, _):
forwardTo(member, t, tag.pos, tag.params);
case FFun(f):
member.excluded = true;
forwardWithFunction(f, tag.pos, tag.params);
}
default:
}
}
function forwardWithFunction(f:Function, pos:Position, params:Array<Expr>) {
var rules = {
call: null,
get: null,
set: null
};
switch (f.expr.expr) {
case EObjectDecl(fields):
for (field in fields)
switch (field.field) {
case 'get': rules.get = field.expr;
case 'set': rules.set = field.expr;
case 'call': rules.call = field.expr;
}
default: f.expr.reject();
}
var filter = makeFilter(params);
for (arg in f.args)
forwardWith(arg.name, rules, arg.type, pos, filter);
}
function forwardWith(id:String, rules:ForwardRules, t:ComplexType, pos:Position, filter:ClassFieldFilter) {
var fields = t.toType(pos).sure().getFields().sure();
for (field in fields)
if (field.isPublic && filter(field) && !hasField(field.name)) {
switch (field.kind) {
case FVar(read, write):
forwardVarWith(id, rules.get, rules.set, isAccessible(read, true), isAccessible(write, false), field.name, field.type.toComplex(), pos);
case FMethod(_):
if (rules.call != null) {
switch (Context.follow(field.type)) {
case TFun(args, ret):
forwardFunctionWith(id, rules.call, pos, field.name, args, ret, field.params);
default:
pos.error('wtf?');
}
}
}
}
}
function forwardToType(t:Type, included:ClassFieldFilter, target:Expr, pos:Position, bound:Null<Bool>) {
for (field in t.getFields().sure())
if (field.isPublic && included(field) && !hasField(field.name)) {
switch (field.kind) {
case FVar(read, write):
forwardVarTo(target, field.name, field.type.toComplex(), read, write, bound);
case FMethod(_):
switch (Context.follow(field.type)) {
case TFun(args, ret):
forwardFunctionTo(target, field.name, args, ret, field.params, bound);
default:
pos.error('wtf?');
}
}
}
}
function forwardTo(to:Member, t:ComplexType, pos:Position, params:Array<Expr>) {
var t = t.toType(pos).sure().reduce(),
target = ['this', to.name].drill(pos),
included = makeFilter(params);
forwardToType(t, included, target, pos, to.isBound);
}
function forwardFunctionWith(id:String, callExpr:Expr, pos:Position, name:String, args:Array<{ name : String, opt : Bool, t : Type }>, ret : Type, params: Array<{ name : String, t : Type }>) {
//TODO: there's a lot of duplication with forwardFunctionTo here
var methodArgs = [],
callArgs = [];
for (arg in args) {
callArgs.push(arg.name.resolve(pos));
methodArgs.push( { name : arg.name, opt : arg.opt, type : arg.t.toComplex(), value : null } );
}
var methodParams = [].toBlock().func().params;//TODO: be less lazy
for (param in params)
methodParams.push( { name : param.name, constraints: [] } );
var argsRemoting = callArgs.slice(0, callArgs.length - 1);
argsRemoting.push( { id:id, name:name}.toExpr() );
argsRemoting.push( callArgs[callArgs.length - 1] );
var call = callExpr.substitute( {
"$argsRemoting":argsRemoting.toArray(),
"$args": callArgs.toArray(),
"$id": id.toExpr(),
"$name": name.toExpr()
});
addField(Member.method(name, call.func(methodArgs, methodParams)));
}
function forwardVarWith(id:String, eGet:Null<Expr>, eSet:Null<Expr>, read:Bool, write:Bool, name, t, pos) {
read = read && eGet != null;
write = write && eSet != null;
if (!(read || write)) return;//I hate guard clauses, but I feel very lazy now
addField(Member.prop(name, t, pos, !read, !write));
var vars = {
"$name": name.toExpr(),
"$id": id.toExpr()
}
if (read)
addField(Member.getter(name, pos, eGet.substitute(vars), t));
if (write)
addField(Member.setter(name, pos, eSet.substitute(vars), t));
}
function forwardFunctionTo(target:Expr, name:String, args:Array<{ name : String, opt : Bool, t : Type }>, ret : Type, params: Array<{ name : String, t : Type }>, bound:Null<Bool>) {
var methodArgs = [],
callArgs = [],
pos = target.pos;
for (arg in args) {
callArgs.push(arg.name.resolve(target.pos));
methodArgs.push( { name : arg.name, opt : arg.opt, type : arg.t.toComplex(true), value : null } );
}
var methodParams = [].toBlock().func().params;//TODO: be less lazy
for (param in params)
methodParams.push( { name : param.name, constraints: [] } );
addField(Member.method(name, target.field(name, pos).call(callArgs, pos).func(methodArgs, ret.toComplex(), methodParams))).isBound = bound;
}
function isAccessible(a:VarAccess, read:Bool) {
return switch(a) {
case AccNormal, AccCall(_): true;
case AccInline: read;
default: false;
}
}
function forwardVarTo(target:Expr, name:String, t:ComplexType, read:VarAccess, write:VarAccess, bound:Null<Bool>) {
var pos = target.pos;
if (!isAccessible(read, true))
pos.error('cannot forward to non-readable field ' + name + ' of ' + t);
addField(Member.prop(name, t, pos, false, !isAccessible(write, false))).isBound = bound;
if (!hasField('get_$name'))
addField(Member.getter(name, pos, target.field(name, pos), t)).isBound = bound;
if (!hasField('set_$name'))
if (isAccessible(write, false))
addField(Member.setter(name, pos, target.field(name, pos).assign('param'.resolve(pos), pos), t));
}
static function and(a, b) {
return function (c) return a(c) && b(c);
}
static function or(a, b) {
return function (c) return a(c) || b(c);
}
static function not(a) {
return function (c) return !a(c);
}
static function one(filters:Iterable<ClassFieldFilter>) {
return function (c) {
for (filter in filters)
if (filter(c))
return true;
return false;
}
}
static function makeFilter(exprs:Array<Expr>) {
return
if (exprs.length == 0)
function (_) return true;
else
one(exprs.map(makeFieldFilter));
}
static function matchRegEx(r:String, opt:String):ClassFieldFilter {
var r = new EReg(r, opt);
return function (field) return r.match(field.name);
}
static public function makeFieldFilter(e:Expr):ClassFieldFilter {
return
switch (e.expr) {
case EArrayDecl(exprs): one(exprs.map(makeFieldFilter));
case EConst(c):
switch (c) {
case CIdent(s):
if (s.startsWith('$'))
switch (s.substr(1)) {
case 'var': function (field:ClassField) return field.isVar();
case 'function': function (field:ClassField) return !field.isVar();
default: e.reject('invalid option');
}
else
function (field) return field.name == s;
case CString(s):
matchRegEx('^' + StringTools.replace(s, '*', '.*') + '$', 'i');
case CRegexp(r, opt):
matchRegEx(r, opt);
default: e.reject('invalid constant');
}
case EBinop(op, e1, e2):
switch (op) {
case OpAnd, OpBoolAnd: and(makeFieldFilter(e1), makeFieldFilter(e2));
case OpOr, OpBoolOr: or(makeFieldFilter(e1), makeFieldFilter(e2));
default: e.reject('invalid operator');
}
case EUnop(op, postfix, arg):
if (postfix || op != OpNot) e.reject();
not(makeFieldFilter(arg));
case EParenthesis(e):
makeFieldFilter(e);
default: e.reject();
}
}
}
package ;
import js.Browser;
import haxe.remoting.ExternalConnection;
import Format;
class JsMain {
public static var cnx = null;
static var ctx = null;
public static var onData: Dynamic;
private static function __init__() : Void {
onData = Reflect.makeVarArgs(__onData);
}
public static function main() {
ctx = new haxe.remoting.Context();
ctx.addObject("main",JsMain);
cnx = ExternalConnection.flashConnect("default", "myFlashObject", ctx);
}
//http://www.verydemo.com/demo_c98_i5393.html
public static function __onData(args: Array<Dynamic>) {
Browser.window.alert("length=" + args[2].id);
Test.bubblesort([1, 2, 9, 7, 6, 0.3], function (err, data) {
cnx = ExternalConnection.flashConnect("default", "myFlashObject", ctx);
cnx.FlashMain.onData.call([err,data,args[2]]);
} );
}
}
package ;
/**
- ...
- @author sonygod
*/
import async.Build;
import async.Async;
import haxe.Timer;
import org.transition9.async.Step;
using org.transition9.async.AsyncLambda;
class Test implements Build
{
static function asyncGet2<T1, T2>(v1:T1, v2:T2, cb){
cb(null, v1, v2);
}
@async(var ret: Array<Float>) public static function bubblesort(array : Array<Float>) {
var swapping = false;
var temp : Float;
while (!swapping) {
swapping = true;
for (i in 0...array.length) {
[]=delay(1);
if (array[i] > array[i+1]) {
temp = array[i+1];
array[i+1] = array[i];
array[i] = temp;
swapping = false;
}
}
}
return array;
}
@async(var ret: Array<Float>) static function asynchronous(){
var arry:Array<Float>;
[ arry] = bubblesort([1337, 1, -465, 3.141592653589793, 789, 69, 789, -132, 3.141592653589793, 465, 789, 0, 27]);
return arry;
}
static function bubblesortSync(array : Array<Float>) {
var swapping = false;
var temp : Float;
while (!swapping) {
swapping = true;
for (i in 0...array.length) {
if (array[i] > array[i+1]) {
temp = array[i+1];
array[i+1] = array[i];
array[i] = temp;
swapping = false;
}
}
}
return array;
}
public static function getResult(err:NodeErr, data:Array<Float>) {
trace("end"+(Timer.stamp()*1000-startTime));
trace(data);
}
@async(var ret:Bool) public static function doFooParallel(arrayData:Array<Float>) {
trace(Timer.stamp() * 10000 + "" + arrayData);
return true;
};
//
@async(var ret:Bool) public static function doFooGroup(?arg1:String) {
trace(Timer.stamp() * 10000 + "doFooGroup" + arg1);
return true;
};
@async(var ret:Bool)public static function doSomethingElseAsync(array) {
trace(Timer.stamp() * 10000 + " doSomethingElseAsync" + array);
return true;
};
@async(var ret:Int) public static function doSomethingElseAsync2(element:Int ) {
trace(element);
return element;
};
@async(var ret:Int,var ret2:String) public static function doSomethingElseAsync3(element:Int ) {
return many(element, "1");
};
public static var startTime:Float;
public static function main() {
var step = new Step();
step.chain([
function () {
bubblesort([2, 1, 4, 7], step.cb);
},
function (err, arrayData) {
doFooParallel(arrayData, step.parallel());
doFooParallel(arrayData, step.parallel());
doFooParallel(arrayData, step.parallel());
}
,function (err, ?arg1,?arg2,?arg3) {
// trace("finish now..."+Timer.stamp()+"arg"+arg1+arg2+arg3);
doFooGroup("group1", step.group());
doFooGroup("group1", step.group());
doFooGroup("group1", step.group());
}
,function (err, args) {
trace("finish"+args);
}
]);
var fromArray = [1, 2, 3, 4];
var onElement = function (element :Int, cb :String->Int->Void) {
platformDelay(100,function () {
cb("Some int=" + element,1);
});
}
var onFinish = function (err :Dynamic, result1:String->Int->Void) {
if (err != null) trace("Oh no: " + err);
trace("result=" + result1);
}
//AsyncLambda.map( fromArray,onElement , onFinish);
doSomethingElseAsync3(1, function(err:String, e:Int,s:String):Void { trace("e=========="+e); } );
}
static inline function delay(ms:Int, cb){
platformDelay(ms, function(){ trace(ms+' passed'); cb(null); });
}
static inline function platformDelay(ms:Int, fun){
if (cpp || neko || php) fun(); #else haxe.Timer.delay(fun, ms); #end
}
}
typedef NodeErr = Null;
/*
*
*
*
*/
package haxe.remoting;
/**
Synchronous communications between Flash and Javascript.
**/
@:expose
class ExternalConnection implements Connection implements Dynamic {
}
typedef CallBackObj = {
id:String,
name:String,
}
typedef CallBackObjWithFun = {
>CallBackObj,
callBack:Dynamic,
}