├── .gitignore ├── src ├── deep │ ├── macro │ │ └── math │ │ │ ├── IOverloadOperator.hx │ │ │ └── OverloadOperator.hx │ └── math │ │ ├── Complex.hx │ │ ├── Quaternion.hx │ │ ├── PointMath.hx │ │ ├── QuaternionMath.hx │ │ ├── ComplexMath.hx │ │ ├── Int32Math.hx │ │ └── Int64Math.hx ├── test │ ├── Main.hx │ ├── OverloadTestInt32.hx │ ├── OverloadTestInt64.hx │ ├── OverloadTestQuaternion.hx │ └── OverloadTestComplex.hx └── example │ └── fractal │ └── Fractal.hx ├── application.nmml ├── assets └── nme.svg ├── overload-operator.hxproj ├── README.md └── nme-readme.txt /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /bin 3 | /Complex.hxml -------------------------------------------------------------------------------- /src/deep/macro/math/IOverloadOperator.hx: -------------------------------------------------------------------------------- 1 | package deep.macro.math; 2 | 3 | /** 4 | * ... 5 | * @author deep 6 | */ 7 | 8 | @:autoBuild(deep.macro.math.OverloadOperator.build()) interface IOverloadOperator 9 | { 10 | 11 | 12 | } -------------------------------------------------------------------------------- /src/test/Main.hx: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | import haxe.unit.TestRunner; 4 | 5 | /** 6 | * ... 7 | * @author deep 8 | */ 9 | class Main 10 | { 11 | static public function main() 12 | { 13 | var r = new TestRunner(); 14 | r.add(new OverloadTestComplex()); 15 | r.add(new OverloadTestQuaternion()); 16 | r.add(new OverloadTestInt32()); 17 | r.add(new OverloadTestInt64()); 18 | r.run(); 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/deep/math/Complex.hx: -------------------------------------------------------------------------------- 1 | package deep.math; 2 | /** 3 | * ... 4 | * @author deep 5 | */ 6 | 7 | class Complex 8 | { 9 | 10 | public var re:Float; 11 | public var im:Float; 12 | 13 | public function new(re:Float = 0, im:Float = 0) 14 | { 15 | this.re = re; 16 | this.im = im; 17 | } 18 | 19 | public function toString() 20 | { 21 | return "[Complex: " + re + ", " + im + "]"; 22 | } 23 | 24 | inline public function clone() 25 | { 26 | return new Complex(re, im); 27 | } 28 | } -------------------------------------------------------------------------------- /application.nmml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /assets/nme.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/deep/math/Quaternion.hx: -------------------------------------------------------------------------------- 1 | package deep.math; 2 | 3 | import deep.macro.math.IOverloadOperator; 4 | 5 | /** 6 | * ... 7 | * @author Simon Krajewski 8 | */ 9 | 10 | class Quaternion 11 | { 12 | public var x:Float; 13 | public var y:Float; 14 | public var z:Float; 15 | public var w:Float; 16 | 17 | public function new(x, y, z, w) 18 | { 19 | this.x = x; 20 | this.y = y; 21 | this.z = z; 22 | this.w = w; 23 | } 24 | 25 | public function getNorm() 26 | { 27 | return Math.sqrt(x * x + y * y + z * z + w * w); 28 | } 29 | 30 | public function normalize() 31 | { 32 | return QuaternionMath.scalarDiv(this, getNorm()); 33 | } 34 | 35 | public function invert() 36 | { 37 | return QuaternionMath.scalar(QuaternionMath.conjugate(this), getNorm()); 38 | } 39 | 40 | public function copy() 41 | { 42 | return new Quaternion(x, y, z, w); 43 | } 44 | 45 | static public function fromAxisAngle(x:Float, y:Float, z:Float, a:Float) 46 | { 47 | var r = Math.sin(a / 2.0); 48 | return new Quaternion(x * r, y * r, z * r, Math.cos(a / 2.0)); 49 | } 50 | 51 | static public function fromYawPitchRoll(yaw:Float, pitch:Float, roll:Float) 52 | { 53 | var x = fromAxisAngle(1, 0, 0, pitch); 54 | var y = fromAxisAngle(0, 1, 0, yaw); 55 | var z = fromAxisAngle(0, 0, 1, roll); 56 | 57 | return QuaternionMath.mul(QuaternionMath.mul(x, y), z); 58 | } 59 | 60 | public function toString() 61 | { 62 | return "[Quaternion " +x + " " +y + " " +z + " " +w + "]"; 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/OverloadTestInt32.hx: -------------------------------------------------------------------------------- 1 | package test; 2 | import deep.macro.math.IOverloadOperator; 3 | import deep.math.Int32Math; 4 | import haxe.Int32; 5 | import haxe.unit.TestCase; 6 | 7 | /** 8 | * ... 9 | * @author deep 10 | */ 11 | 12 | class OverloadTestInt32 extends TestCase, implements IOverloadOperator 13 | { 14 | 15 | public function new() 16 | { 17 | super(); 18 | } 19 | 20 | function test1() 21 | { 22 | var i1 = Int32.ofInt(30); 23 | var i2 = Int32.ofInt(3000); 24 | 25 | assertTrue(i1 + i2 == 3030); 26 | assertTrue(i1 < i2); 27 | assertFalse(i1 > i2); 28 | assertTrue(i2 > i1); 29 | assertFalse(i2 < i1); 30 | 31 | assertTrue(i1 == 30); 32 | assertTrue(i2 == 3000); 33 | assertTrue(i1 != i2); 34 | 35 | assertTrue(i1 * i2 == 90000); 36 | assertTrue(i2 / i1 == 100); 37 | 38 | assertTrue(i2 % i1 == 0); 39 | assertTrue(i1 % i2 == 30); 40 | 41 | assertTrue(i1 << 1 == 60); 42 | assertTrue(i2 >> 1 == 1500); 43 | 44 | assertTrue( -i2 >> 1 == -1500); 45 | 46 | i1 <<= 2; 47 | assertTrue(i1 == 120); 48 | i1 >>= 2; 49 | assertTrue(i1 == 30); 50 | 51 | i1++; 52 | assertTrue(i1 == 31); 53 | --i1; 54 | assertTrue(i1 == 30); 55 | 56 | i1 += 10; 57 | assertTrue(i1 == 40); 58 | i1 -= 10; 59 | assertTrue(i1 == 30); 60 | 61 | assertTrue( -i1 == -30); 62 | 63 | assertTrue(i1 & i2 == 30 & 3000); 64 | assertTrue(i1 | i2 == 30 | 3000); 65 | assertTrue(i1 ^ i2 == 30 ^ 3000); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /src/test/OverloadTestInt64.hx: -------------------------------------------------------------------------------- 1 | package test; 2 | import deep.macro.math.IOverloadOperator; 3 | import deep.math.Int64Math; 4 | import haxe.Int64; 5 | import haxe.unit.TestCase; 6 | 7 | /** 8 | * ... 9 | * @author deep 10 | */ 11 | 12 | class OverloadTestInt64 extends TestCase, implements IOverloadOperator 13 | { 14 | 15 | public function new() 16 | { 17 | super(); 18 | } 19 | 20 | function test1() 21 | { 22 | var i1 = Int64.ofInt(30); 23 | var i2 = Int64.ofInt(3000); 24 | 25 | assertTrue(i1 + i2 == 3030); 26 | assertTrue(i1 < i2); 27 | assertFalse(i1 > i2); 28 | assertTrue(i2 > i1); 29 | assertFalse(i2 < i1); 30 | 31 | assertTrue(i1 == 30); 32 | assertTrue(i2 == 3000); 33 | assertTrue(i1 != i2); 34 | 35 | assertTrue(i1 * i2 == 90000); 36 | assertTrue(i2 / i1 == 100); 37 | 38 | assertTrue(i2 % i1 == 0); 39 | assertTrue(i1 % i2 == 30); 40 | 41 | assertTrue(i1 << 1 == 60); 42 | assertTrue(i2 >> 1 == 1500); 43 | 44 | assertTrue( -i2 >> 1 == -1500); 45 | 46 | i1 <<= 2; 47 | assertTrue(i1 == 120); 48 | i1 >>= 2; 49 | assertTrue(i1 == 30); 50 | 51 | i1++; 52 | assertTrue(i1 == 31); 53 | --i1; 54 | assertTrue(i1 == 30); 55 | 56 | i1 += 10; 57 | assertTrue(i1 == 40); 58 | i1 -= 10; 59 | assertTrue(i1 == 30); 60 | 61 | assertTrue( -i1 == -30); 62 | 63 | assertTrue(i1 & i2 == 30 & 3000); 64 | assertTrue(i1 | i2 == 30 | 3000); 65 | assertTrue(i1 ^ i2 == 30 ^ 3000); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /src/deep/math/PointMath.hx: -------------------------------------------------------------------------------- 1 | package deep.math; 2 | import nme.geom.Point; 3 | 4 | /** 5 | * ... 6 | * @author deep 7 | */ 8 | 9 | class PointMath 10 | { 11 | 12 | @op("+", true) public static function add(a:Point, b:Point):Point 13 | { 14 | return new Point(a.x + b.x, a.y + b.y); 15 | } 16 | 17 | @op("+", true) public static function addScalarFloat(a:Point, b:Float):Point 18 | { 19 | return new Point(a.x + b, a.y + b); 20 | } 21 | 22 | @op("+", true) public static function addScalarInt(a:Point, b:Int):Point 23 | { 24 | return new Point(a.x + b, a.y + b); 25 | } 26 | 27 | @op("-", true) public static function sub(a:Point, b:Point):Point 28 | { 29 | return new Point(a.x - b.x, a.y - b.y); 30 | } 31 | 32 | @op("-", false) public static function subScalarFloat(a:Point, b:Float):Point 33 | { 34 | return new Point(a.x - b, a.y - b); 35 | } 36 | 37 | @op("-", false) public static function subScalarInt(a:Point, b:Int):Point 38 | { 39 | return new Point(a.x - b, a.y - b); 40 | } 41 | 42 | @op("/", false) public static function divScalarInt(a:Point, b:Int):Point 43 | { 44 | return new Point(a.x / b, a.y / b); 45 | } 46 | 47 | @op("/", false) public static function divScalarFloat(a:Point, b:Float):Point 48 | { 49 | return new Point(a.x / b, a.y / b); 50 | } 51 | 52 | @op("*", true) public static function multScalarInt(a:Point, b:Int):Point 53 | { 54 | return new Point(a.x * b, a.y * b); 55 | } 56 | 57 | @op("*", true) public static function multScalarFloat(a:Point, b:Float):Point 58 | { 59 | return new Point(a.x * b, a.y * b); 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /overload-operator.hxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Looks Simn fork first - https://github.com/Simn/hxop 2 | 3 | ## haXe operator overloading tool (alpha) 4 | 5 | Macros 6 | 7 | @op(operator, [commutative=false]) 8 | 9 | @noOverload - ignore 10 | 11 | Support operators 12 | 13 | ``` 14 | + - * / % += -= *= /= %= 15 | < > == != <= >= 16 | & && | || ^ ! 17 | << >> <<< ~ 18 | ... 19 | ++x x++ --x x-- -x 20 | ``` 21 | 22 | ## Demo code: 23 | 24 | * ComplexMath.hx 25 | 26 | ``` 27 | ... 28 | 29 | @op("+", true) inline static public function add(a:Complex, b:Complex):Complex 30 | { 31 | return new Complex(a.re + b.re, a.im + b.im); 32 | } 33 | 34 | @op("+", true) inline static public function addFloat(a:Complex, b:Float):Complex 35 | { 36 | return new Complex(a.re + b, a.im); 37 | } 38 | 39 | @op("-x") inline static public function neg(a:Complex):Complex 40 | { 41 | a.re = -a.re; 42 | a.im = -a.im; 43 | return a; 44 | } 45 | 46 | @op("/=", true) inline static public function idiv(a:Complex, b:Complex):Complex 47 | { 48 | var are = a.re; 49 | var bre = b.re; 50 | var div = 1 / (bre * bre + b.im * b.im); 51 | a.re = (are * bre + a.im * b.im) * div; 52 | a.im = (are * b.im + a.im * bre) * div; 53 | return a; 54 | } 55 | 56 | @op("==", true) public static function eq(a:Complex, b:Complex):Bool 57 | { 58 | return a.re == b.re && a.im == b.im; 59 | } 60 | ... 61 | ``` 62 | 63 | * Main.hx 64 | 65 | ``` 66 | ... 67 | class Main implements IOverloadOperator 68 | { 69 | // noOverload - ignore this method 70 | @noOverload static public function main() 71 | { 72 | new Main(); 73 | } 74 | 75 | public function new() 76 | { 77 | var c = new Complex(0, 1); 78 | c *= new Complex(0, 1); // c = ComplexMath.imult(c, new Complex(0, 1)); 79 | trace(c); 80 | } 81 | } 82 | ``` 83 | 84 | ## Supported maths 85 | 86 | * [ComplexMath](https://github.com/profelis/overload-operator/blob/master/src/deep/math/ComplexMath.hx) 87 | * [QuaternionMath](https://github.com/profelis/overload-operator/blob/master/src/deep/math/QuaternionMath.hx) 88 | * [Int32Math](https://github.com/profelis/overload-operator/blob/master/src/deep/math/Int32Math.hx) 89 | * [Int64Math](https://github.com/profelis/overload-operator/blob/master/src/deep/math/Int64Math.hx) 90 | * Beta [PointMath](https://github.com/profelis/overload-operator/blob/master/src/deep/math/PointMath.hx) -------------------------------------------------------------------------------- /nme-readme.txt: -------------------------------------------------------------------------------- 1 | About NME 2 | 3 | Building a game or application with NME is almost like writing for a single platform. However, 4 | when you are ready to publish your application, you can choose between targets like iOS, webOS, 5 | Android, Windows, Mac, Linux and Flash Player. 6 | 7 | Instead of using the lowest common denominator between platforms with a "universal" runtime, 8 | NME projects are compiled as SWF bytecode or C++ applications, using the Haxe language compiler 9 | and the standard C++ compiler toolchain for each platform. 10 | 11 | Read more: 12 | http://www.haxenme.org/ 13 | 14 | Development 15 | 16 | NME is very close to Flash API but using 'nme' as the root package (ie. nme.display.Sprite). 17 | http://www.haxenme.org/api/ 18 | 19 | Just code like you would code a Flash application, with the limitation that you can only use 20 | the drawing API, bitmaps (see below) and TextFields. 21 | 22 | In NME 3.0, SWFs and videos aren't supported yet. 23 | 24 | Assets 25 | 26 | Place all your images, sounds, fonts in /assets and access them in your code using the 27 | global Assets class which abstracts assets management for all platforms: 28 | 29 | var img = new Bitmap(Assets.getBitmapData("assets/my-image.png")); 30 | addChild(img); 31 | 32 | Tutorials: 33 | http://www.haxenme.org/developers/tutorials/ 34 | 35 | Debugging 36 | 37 | By default your project targets Flash so you'll be able to add breakpoints and debug your app 38 | like any AS3 project. 39 | 40 | Project configuration, libraries, classpaths 41 | 42 | NME integration in FlashDevelop is still early and you'll have to configure the classpath and 43 | haxelibs both in the FD project and in the build.nmml file. 44 | 45 | Native targets 46 | 47 | Change the NME target in your Project Properties > Test Project > Edit... 48 | Enter a valid target in the field, like: 49 | - flash 50 | - cpp 51 | - android 52 | 53 | Attention, for non-Flash targets you'll need to install additional compilers & SDKs: 54 | http://www.haxenme.org/developers/get-started/ 55 | 56 | Tips: 57 | - in C++ expect first compilation to be very long as it first compiles the whole NME API, 58 | - if a change is not taken in account, delete everything in /bin to start a fresh compilation. 59 | 60 | -------------------------------------------------------------------------------- /src/example/fractal/Fractal.hx: -------------------------------------------------------------------------------- 1 | package example.fractal; 2 | import deep.macro.math.IOverloadOperator; 3 | import deep.math.Complex; 4 | import deep.math.ComplexMath; 5 | import haxe.Timer; 6 | import nme.display.Bitmap; 7 | import nme.display.BitmapData; 8 | import nme.display.Sprite; 9 | import nme.display.StageAlign; 10 | import nme.display.StageScaleMode; 11 | import nme.Lib; 12 | 13 | /** 14 | * ... 15 | * @author deep 16 | */ 17 | 18 | using deep.math.ComplexMath; 19 | 20 | class Fractal implements IOverloadOperator 21 | { 22 | @noOverload public static function main() 23 | { 24 | new Fractal(); 25 | } 26 | 27 | @noOverload public function new() 28 | { 29 | var s = Lib.current.stage; 30 | s.scaleMode = StageScaleMode.NO_SCALE; 31 | s.align = StageAlign.TOP_LEFT; 32 | 33 | 34 | var bd = new BitmapData(800, 800, false, 0xFFFFFF); 35 | fractal(45, new Complex(-0.008, 0.697), bd, true); 36 | 37 | s.addChild(new Bitmap(bd)); 38 | } 39 | 40 | var timer:Timer; 41 | 42 | function fractal(randomSeed:Int, c:Complex, res:BitmapData, timed:Bool = false):Void 43 | { 44 | if (timer != null) 45 | { 46 | timer.stop(); 47 | timer = null; 48 | } 49 | var w = Math.round(res.width / 2); 50 | var h = Math.round(res.height / 2); 51 | var z = new Complex(); 52 | var i:Int; 53 | var j = -h; 54 | var k:Int; 55 | var step = 5; 56 | 57 | var ts = Timer.stamp(); 58 | 59 | function tick():Void 60 | { 61 | res.lock(); 62 | for (t in 0...step) 63 | { 64 | i = -w; 65 | while (i <= w) 66 | { 67 | z.re = i / w; 68 | z.im = j / h; 69 | k = 0; 70 | while (k < randomSeed) 71 | { 72 | z.sqr(); 73 | z += c; 74 | 75 | if (z.abs2() > 1.0E10) break; 76 | k++; 77 | } 78 | res.setPixel(i + w, j + h, fromHSV((k / randomSeed) * 360)); 79 | i++; 80 | } 81 | j++; 82 | if (j > h) 83 | { 84 | res.unlock(); 85 | if (timer != null) 86 | { 87 | timer.stop(); 88 | timer = null; 89 | trace("render time: " + (Timer.stamp() - ts)); 90 | } 91 | return; 92 | } 93 | } 94 | res.unlock(); 95 | } 96 | if (!timed) 97 | { 98 | for (k in 0...Std.int(2 * h / step)) tick(); 99 | trace("render time: " + (Timer.stamp() - ts)); 100 | } 101 | else 102 | { 103 | timer = new Timer(30); 104 | timer.run = tick; 105 | } 106 | } 107 | 108 | @noOverload inline static function fromHSV(hue:Float):Int 109 | { 110 | var h:Float = (hue + 360) % 360; 111 | var v:Float = 1; 112 | var hi:Int = Math.round(h / 60) % 6; 113 | var f:Float = h / 60 - hi; 114 | var p:Float = 0; 115 | var q:Float = 1 - f; 116 | var t:Float = f; 117 | if (hi == 0) return fromFloats(v, t, p); 118 | else if (hi == 1) return fromFloats(q, v, p); 119 | else if (hi == 2) return fromFloats(p, v, t); 120 | else if (hi == 3) return fromFloats(p, q, v); 121 | else if (hi == 4) return fromFloats(t, p, v); 122 | else if (hi == 5) return fromFloats(v, p, q); 123 | else return 0; 124 | } 125 | 126 | @noOverload 127 | inline static function fromFloats(red:Float, green:Float, blue:Float):Int 128 | { 129 | return 0x10000*Math.round(red*0xFF) + 0x100*Math.round(green*0xFF) + Math.round(blue*0xFF); 130 | } 131 | } -------------------------------------------------------------------------------- /src/deep/math/QuaternionMath.hx: -------------------------------------------------------------------------------- 1 | package deep.math; 2 | 3 | /** 4 | * ... 5 | * @author Simon Krajewski 6 | */ 7 | 8 | class QuaternionMath 9 | { 10 | // basic arithmetic 11 | 12 | @op('+', true) inline static public function add(lhs:Quaternion, rhs:Quaternion) 13 | { 14 | return new Quaternion(lhs.x + rhs.x, 15 | lhs.y + rhs.y, 16 | lhs.z + rhs.z, 17 | lhs.w + rhs.w); 18 | } 19 | 20 | @op('-', true) inline static public function sub(lhs:Quaternion, rhs:Quaternion) 21 | { 22 | return new Quaternion(lhs.x - rhs.x, 23 | lhs.y - rhs.y, 24 | lhs.z - rhs.z, 25 | lhs.w - rhs.w); 26 | } 27 | 28 | @op('*', true) inline static public function mul(lhs:Quaternion, rhs:Quaternion) 29 | { 30 | return new Quaternion( 31 | rhs.x * lhs.w + rhs.w * lhs.x + rhs.z * lhs.y - rhs.y * lhs.z, 32 | rhs.y * lhs.w + rhs.w * lhs.y + rhs.x * lhs.z - rhs.z * lhs.x, 33 | rhs.z * lhs.w + rhs.w * lhs.z + rhs.y * lhs.x - rhs.x * lhs.y, 34 | rhs.w * lhs.w - rhs.x * lhs.x - rhs.y * lhs.y - rhs.z * lhs.z 35 | ); 36 | } 37 | 38 | // arithmetic assignment versions 39 | 40 | @op('+=', true) inline static public function addAssign(lhs:Quaternion, rhs:Quaternion) 41 | { 42 | lhs.x += rhs.x; 43 | lhs.y += rhs.y; 44 | lhs.z += rhs.z; 45 | lhs.w += rhs.w; 46 | return lhs; 47 | } 48 | 49 | @op('-=', true) inline static public function subAssign(lhs:Quaternion, rhs:Quaternion) 50 | { 51 | lhs.x -= rhs.x; 52 | lhs.y -= rhs.y; 53 | lhs.z -= rhs.z; 54 | lhs.w -= rhs.w; 55 | return lhs; 56 | } 57 | 58 | @op('*=', true) inline static public function mulAssign(lhs:Quaternion, rhs:Quaternion) 59 | { 60 | lhs.x = rhs.x * lhs.w + rhs.w * lhs.x + rhs.z * lhs.y - rhs.y * lhs.z; 61 | lhs.y = rhs.y * lhs.w + rhs.w * lhs.y + rhs.x * lhs.z - rhs.z * lhs.x; 62 | lhs.z = rhs.z * lhs.w + rhs.w * lhs.z + rhs.y * lhs.x - rhs.x * lhs.y; 63 | lhs.w = rhs.w * lhs.w - rhs.x * lhs.x - rhs.y * lhs.y - rhs.z * lhs.z; 64 | return lhs; 65 | } 66 | 67 | // conjugation 68 | 69 | @op('-x') inline static public function invert(rhs:Quaternion) 70 | { 71 | return new Quaternion( -rhs.x, -rhs.y, -rhs.z, -rhs.w); 72 | } 73 | 74 | @op('~x') inline static public function conjugate(rhs:Quaternion) 75 | { 76 | return new Quaternion( -rhs.x, -rhs.y, -rhs.z, rhs.w); 77 | } 78 | 79 | // rotation 80 | 81 | @op('<<', true) inline static public function rotate(point:Quaternion, rotation:Quaternion) 82 | { 83 | return mul(mul(rotation, point), conjugate(rotation)); 84 | } 85 | 86 | // scalar 87 | 88 | @op("*", true) inline static public function scalar(quat:Quaternion, scalar:Float) 89 | { 90 | return new Quaternion(quat.x * scalar, quat.y * scalar, quat.z * scalar, quat.w * scalar); 91 | } 92 | 93 | @op("/", false) inline static public function scalarDiv(quat:Quaternion, scalar:Float) 94 | { 95 | return new Quaternion(quat.x / scalar, quat.y / scalar, quat.z / scalar, quat.w / scalar); 96 | } 97 | 98 | // scalar assignment versions 99 | 100 | @op("*=", false) inline static public function scalarAssign(quat:Quaternion, scalar:Float) 101 | { 102 | quat.x *= scalar; 103 | quat.y *= scalar; 104 | quat.z *= scalar; 105 | quat.w *= scalar; 106 | return quat; 107 | } 108 | 109 | @op("/=", false) inline static public function scalarDivAssign(quat:Quaternion, scalar:Float) 110 | { 111 | quat.x /= scalar; 112 | quat.y /= scalar; 113 | quat.z /= scalar; 114 | quat.w /= scalar; 115 | return quat; 116 | } 117 | 118 | // comparison 119 | 120 | @op("==", true) inline static public function equals(lhs:Quaternion, rhs:Quaternion) 121 | { 122 | return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; 123 | } 124 | 125 | @op("!=", true) inline static public function notEquals(lhs:Quaternion, rhs:Quaternion) 126 | { 127 | return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; 128 | } 129 | 130 | static public inline function dot(q1:Quaternion, q2:Quaternion) 131 | { 132 | return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z ; 133 | } 134 | 135 | static public inline function slerp(q1:Quaternion, q2:Quaternion, t:Float) 136 | { 137 | var angle = dot(q1, q2); 138 | if (angle == 0) 139 | return q1.copy(); 140 | var f1 = Math.sin((1 - t) * angle) / Math.sin(angle); 141 | var f2 = Math.sin(t * angle) / Math.sin(angle); 142 | 143 | return add(scalar(q1, f1), scalar(q2, f2)); 144 | } 145 | } -------------------------------------------------------------------------------- /src/deep/math/ComplexMath.hx: -------------------------------------------------------------------------------- 1 | package deep.math; 2 | 3 | /** 4 | * ... 5 | * @author deep 6 | */ 7 | 8 | class ComplexMath 9 | { 10 | 11 | @op("+", true) inline static public function add(a:Complex, b:Complex):Complex 12 | { 13 | return new Complex(a.re + b.re, a.im + b.im); 14 | } 15 | 16 | @op("+", true) inline static public function addFloat(a:Complex, b:Float):Complex 17 | { 18 | return new Complex(a.re + b, a.im); 19 | } 20 | 21 | @op("-", true) inline static public function sub(a:Complex, b:Complex):Complex 22 | { 23 | return new Complex(a.re - b.re, a.im - b.im); 24 | } 25 | 26 | @op("-x") inline static public function neg(a:Complex):Complex 27 | { 28 | return new Complex( -a.re, -a.im); 29 | } 30 | 31 | @op("-", false) inline static public function subFloat(a:Complex, b:Float):Complex 32 | { 33 | return new Complex(a.re - b, a.im); 34 | } 35 | 36 | @op("*", true) inline static public function mult(a:Complex, b:Complex):Complex 37 | { 38 | return new Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re); 39 | } 40 | 41 | @op("*", true) inline static public function multFloat(a:Complex, b:Float):Complex 42 | { 43 | return new Complex(a.re * b, a.im * b); 44 | } 45 | 46 | @op("/", true) inline static public function div(a:Complex, b:Complex):Complex 47 | { 48 | var div = 1 / abs2(b); 49 | return new Complex((a.re * b.re + a.im * b.im) * div, (a.re * b.im + a.im * b.re) * div); 50 | } 51 | 52 | @op("/", false) inline static public function divFloat(a:Complex, b:Float):Complex 53 | { 54 | return new Complex(a.re / b, a.im / b); 55 | } 56 | 57 | @op("+=", true) inline static public function iadd(a:Complex, b:Complex):Complex 58 | { 59 | a.re += b.re; 60 | a.im += b.im; 61 | return a; 62 | } 63 | 64 | @op("+=", false) inline static public function iaddFloat(a:Complex, b:Float):Complex 65 | { 66 | a.re += b; 67 | return a; 68 | } 69 | 70 | @op("-=", true) inline static public function isub(a:Complex, b:Complex):Complex 71 | { 72 | a.re -= b.re; 73 | a.im -= b.im; 74 | return a; 75 | } 76 | 77 | @op("-=", false) inline static public function isubFloat(a:Complex, b:Float):Complex 78 | { 79 | a.re -= b; 80 | return a; 81 | } 82 | 83 | @op("*=", true) inline static public function imult(a:Complex, b:Complex):Complex 84 | { 85 | var are = a.re; 86 | var bre = b.re; 87 | a.re = are * bre - a.im * b.im; 88 | a.im = are * b.im + a.im * bre; 89 | return a; 90 | } 91 | 92 | @op("*=", false) inline static public function imultFloat(a:Complex, b:Float):Complex 93 | { 94 | a.re *= b; 95 | a.im *= b; 96 | return a; 97 | } 98 | 99 | @op("/=", true) inline static public function idiv(a:Complex, b:Complex):Complex 100 | { 101 | var are = a.re; 102 | var bre = b.re; 103 | var div = 1 / abs2(b); 104 | a.re = (are * bre + a.im * b.im) * div; 105 | a.im = (are * b.im + a.im * bre) * div; 106 | return a; 107 | } 108 | 109 | @op("/=", false) inline static public function idivFloat(a:Complex, b:Float):Complex 110 | { 111 | a.re /= b; 112 | a.im /= b; 113 | return a; 114 | } 115 | 116 | @op("==", true) public static function eq(a:Complex, b:Complex):Bool 117 | { 118 | return a.re == b.re && a.im == b.im; 119 | } 120 | 121 | @op("==", true) public static function eqFloat(a:Complex, b:Float):Bool 122 | { 123 | return a.re == b && a.im == 0; 124 | } 125 | 126 | @op("!=", true) public static function notEq(a:Complex, b:Complex):Bool 127 | { 128 | return a.re != b.re || a.im != b.im; 129 | } 130 | 131 | @op("!=", true) public static function notEqFloat(a:Complex, b:Float):Bool 132 | { 133 | return a.re != b || a.im != 0; 134 | } 135 | 136 | @op("<<=") public static function clone(a:Complex, b:Complex):Complex 137 | { 138 | a.re = b.re; 139 | a.im = b.im; 140 | return a; 141 | } 142 | 143 | inline static public function sqr(c:Complex):Complex 144 | { 145 | var tim = 2 * c.re * c.im; 146 | c.re = c.re * c.re - c.im * c.im; 147 | c.im = tim; 148 | 149 | return c; 150 | } 151 | 152 | inline static public function abs(c:Complex):Float 153 | { 154 | return Math.sqrt(c.re * c.re + c.im * c.im); 155 | } 156 | 157 | inline static public function abs2(c:Complex):Float 158 | { 159 | return c.re * c.re + c.im * c.im; 160 | } 161 | 162 | } -------------------------------------------------------------------------------- /src/test/OverloadTestQuaternion.hx: -------------------------------------------------------------------------------- 1 | package test; 2 | import deep.math.QuaternionMath; 3 | import deep.math.Quaternion; 4 | import deep.macro.math.IOverloadOperator; 5 | import haxe.unit.TestCase; 6 | 7 | /** 8 | * ... 9 | * @author Simon Krajewski 10 | */ 11 | 12 | class OverloadTestQuaternion extends TestCase, implements IOverloadOperator 13 | { 14 | public function testGetNorm() 15 | { 16 | var quat = new Quaternion(5, 3, 1, 1); 17 | assertEquals(6.0, quat.getNorm()); 18 | } 19 | 20 | public function testNormalize() 21 | { 22 | var quat = new Quaternion(10, 0, 0, 0); 23 | var quatNorm = quat.normalize(); 24 | assertEquals(1.0, quatNorm.x); 25 | assertEquals(0.0, quatNorm.y); 26 | assertEquals(0.0, quatNorm.z); 27 | assertEquals(0.0, quatNorm.w); 28 | } 29 | 30 | public function testAdd() 31 | { 32 | var quat = new Quaternion(1, 2, 3, 4) + new Quaternion(1, 1, 1, 1); 33 | assertEquals(2.0, quat.x); 34 | assertEquals(3.0, quat.y); 35 | assertEquals(4.0, quat.z); 36 | assertEquals(5.0, quat.w); 37 | 38 | quat += new Quaternion(1, 2, 3, 4); 39 | assertEquals(3.0, quat.x); 40 | assertEquals(5.0, quat.y); 41 | assertEquals(7.0, quat.z); 42 | assertEquals(9.0, quat.w); 43 | } 44 | 45 | public function testSubtract() 46 | { 47 | var quat = new Quaternion(1, 2, 3, 4) - new Quaternion(1, 1, 1, 1); 48 | assertEquals(0.0, quat.x); 49 | assertEquals(1.0, quat.y); 50 | assertEquals(2.0, quat.z); 51 | assertEquals(3.0, quat.w); 52 | 53 | quat -= new Quaternion(4, 3, 2, 1); 54 | assertEquals(-4.0, quat.x); 55 | assertEquals(-2.0, quat.y); 56 | assertEquals(0.0, quat.z); 57 | assertEquals(2.0, quat.w); 58 | } 59 | 60 | public function testEquals() 61 | { 62 | var quat1 = new Quaternion(1, 2, 3, 9); 63 | var quat2 = new Quaternion(1, 2, 3, 9); 64 | assertTrue(quat1 == quat2); 65 | assertTrue(quat1 == quat1); 66 | assertFalse(quat1 == new Quaternion(1, 2, 3, 8)); 67 | } 68 | 69 | public function testNotEquals() 70 | { 71 | var quat1 = new Quaternion(1, 2, 3, 9); 72 | var quat2 = new Quaternion(1, 2, 3, 9); 73 | assertFalse(quat1 != quat2); 74 | assertFalse(quat1 != quat1); 75 | assertTrue(quat1 != new Quaternion(1, 2, 3, 8)); 76 | } 77 | 78 | public function testConjugateInvert() 79 | { 80 | var quat = new Quaternion(1, 2, 3, 4); 81 | var quatConj = ~quat; 82 | var quatInv = -quat; 83 | 84 | assertEquals( -1.0, quatConj.x); 85 | assertEquals( -2.0, quatConj.y); 86 | assertEquals( -3.0, quatConj.z); 87 | assertEquals( 4.0, quatConj.w); 88 | 89 | assertEquals( -1.0, quatInv.x); 90 | assertEquals( -2.0, quatInv.y); 91 | assertEquals( -3.0, quatInv.z); 92 | assertEquals( -4.0, quatInv.w); 93 | } 94 | 95 | public function testRotate() 96 | { 97 | var point = new Quaternion(0, 1, 0, 0); 98 | 99 | var rotate = Quaternion.fromYawPitchRoll(0, 0, Math.PI / 2); 100 | // 90° roll from (0, 1, 0) to (-1, 0, 0) 101 | var rotated = point << rotate; 102 | assertFloatEquals( -1.0, rotated.x); 103 | assertFloatEquals( 0.0, rotated.y); 104 | assertFloatEquals( 0.0, rotated.z); 105 | 106 | rotate = Quaternion.fromYawPitchRoll(0, 0, Math.PI); 107 | // 180° roll from (0, 1, 0) to (0, -1, 0) 108 | var rotated = point << rotate; 109 | assertFloatEquals( 0.0, rotated.x); 110 | assertFloatEquals( -1.0, rotated.y); 111 | assertFloatEquals( 0.0, rotated.z); 112 | } 113 | 114 | public function testScalar() 115 | { 116 | var quat = new Quaternion(1, 2, 3, 4); 117 | var scaledQuat = quat * 5.0; 118 | assertEquals(5.0, scaledQuat.x); 119 | assertEquals(10.0, scaledQuat.y); 120 | assertEquals(15.0, scaledQuat.z); 121 | assertEquals(20.0, scaledQuat.w); 122 | assertTrue(5.0 * quat == scaledQuat); 123 | 124 | scaledQuat = quat / 4.0; 125 | assertEquals(1 / 4, scaledQuat.x); 126 | assertEquals(2 / 4, scaledQuat.y); 127 | assertEquals(3/ 4, scaledQuat.z); 128 | assertEquals(1.0, scaledQuat.w); 129 | 130 | quat *= 2.0; 131 | assertEquals(2.0, quat.x); 132 | assertEquals(4.0, quat.y); 133 | assertEquals(6.0, quat.z); 134 | assertEquals(8.0, quat.w); 135 | 136 | quat /= 2.0; 137 | assertEquals(1.0, quat.x); 138 | assertEquals(2.0, quat.y); 139 | assertEquals(3.0, quat.z); 140 | assertEquals(4.0, quat.w); 141 | } 142 | 143 | public function testCombinedRotation() 144 | { 145 | var point = new Quaternion(0, 1, 0, 0); 146 | var rotate1 = Quaternion.fromYawPitchRoll(0, 0, Math.PI / 2); 147 | var rotate2 = Quaternion.fromYawPitchRoll(Math.PI, 0, 0); 148 | var rotate = rotate2 * rotate1; 149 | 150 | // rotate (0, 1, 0) 90° about z to (-1, 0, 0) 151 | // then rotate this 180° about x to (1, 0, 0) 152 | var rotated = point << rotate; 153 | assertFloatEquals(1.0, rotated.x); 154 | assertFloatEquals(0.0, rotated.y); 155 | assertFloatEquals(0.0, rotated.z); 156 | } 157 | 158 | function assertFloatEquals(ex:Float, act:Float) 159 | assertTrue(Math.abs(act - ex) < 0.00000001) 160 | } -------------------------------------------------------------------------------- /src/deep/math/Int32Math.hx: -------------------------------------------------------------------------------- 1 | package deep.math; 2 | import haxe.Int32; 3 | 4 | /** 5 | * ... 6 | * @author deep 7 | */ 8 | 9 | class Int32Math 10 | { 11 | 12 | @op("+", true) inline static public var add = Int32.add; 13 | 14 | @op("+", true) inline static public function addInt(a:Int32, b:Int):Int32 15 | { 16 | return Int32.add(a, Int32.ofInt(b)); 17 | } 18 | 19 | @op("-", true) inline static public var sub = Int32.sub; 20 | 21 | @op("-", false) inline static public function subInt(a:Int32, b:Int):Int32 22 | { 23 | return Int32.sub(a, Int32.ofInt(b)); 24 | } 25 | 26 | @op("*", true) inline static public var mult = Int32.mul; 27 | 28 | @op("*", true) inline static public function multInt(a:Int32, b:Int):Int32 29 | { 30 | return Int32.mul(a, Int32.ofInt(b)); 31 | } 32 | 33 | @op("/", true) inline static public var div = Int32.div; 34 | 35 | @op("/", false) inline static public function divInt(a:Int32, b:Int):Int32 36 | { 37 | return Int32.div(a, Int32.ofInt(b)); 38 | } 39 | 40 | @op("%", true) inline static public var mod = Int32.mod; 41 | 42 | @op("%", false) inline static public function modInt(a:Int32, b:Int):Int32 43 | { 44 | return Int32.mod(a, Int32.ofInt(b)); 45 | } 46 | 47 | @op("+=", true) inline static public var iadd = Int32.add; 48 | 49 | @op("+=", false) inline static public function iaddInt(a:Int32, b:Int):Int32 50 | { 51 | return Int32.add(a, Int32.ofInt(b)); 52 | } 53 | 54 | @op("-=", true) inline static public var isub = Int32.sub; 55 | 56 | @op("-=", false) inline static public function isubInt(a:Int32, b:Int):Int32 57 | { 58 | return Int32.sub(a, Int32.ofInt(b)); 59 | } 60 | 61 | @op("*=", true) inline static public var imult = Int32.mul; 62 | 63 | @op("*=", false) inline static public function imultInt(a:Int32, b:Int):Int32 64 | { 65 | return Int32.mul(a, Int32.ofInt(b)); 66 | } 67 | 68 | @op("/=", true) inline static public var idiv = Int32.div; 69 | 70 | @op("/=", false) inline static public function idivInt(a:Int32, b:Int):Int32 71 | { 72 | return Int32.div(a, Int32.ofInt(b)); 73 | } 74 | 75 | @op("%=", true) inline static public var imod = Int32.mod; 76 | 77 | @op("%=", false) inline static public function imodInt(a:Int32, b:Int):Int32 78 | { 79 | return Int32.mod(a, Int32.ofInt(b)); 80 | } 81 | 82 | @op("<<", true) inline static public var shl = Int32.shl; 83 | @op("<<=", true) inline static public var ishl = Int32.shl; 84 | @op(">>", true) inline static public var shr = Int32.shr; 85 | @op(">>=", true) inline static public var ishr = Int32.shr; 86 | @op(">>>", true) inline static public var ushr = Int32.ushr; 87 | @op(">>>=", true) inline static public var iushr = Int32.ushr; 88 | 89 | @op("&", true) inline static public var and = Int32.and; 90 | @op("&=", true) inline static public var iand = Int32.and; 91 | @op("|", true) inline static public var or = Int32.or; 92 | @op("|=", true) inline static public var ior = Int32.or; 93 | @op("^", true) inline static public var xor = Int32.xor; 94 | @op("^=", true) inline static public var ixor = Int32.xor; 95 | 96 | @op("-x") inline static public var neg = Int32.neg; 97 | 98 | @op("++x", false) inline static public function inc(a:Int32):Int32 99 | { 100 | return Int32.add(a, Int32.ofInt(1)); 101 | } 102 | 103 | @op("x++", false) inline static public function pinc(a:Int32):Int32 104 | { 105 | return Int32.add(a, Int32.ofInt(1)); 106 | } 107 | 108 | @op("--x", false) inline static public function dec(a:Int32):Int32 109 | { 110 | return Int32.sub(a, Int32.ofInt(1)); 111 | } 112 | 113 | @op("x--", false) inline static public function pdec(a:Int32):Int32 114 | { 115 | return Int32.sub(a, Int32.ofInt(1)); 116 | } 117 | 118 | @op(">", false) inline static public function gt(a:Int32, b:Int32):Bool 119 | { 120 | return Int32.compare(a, b) > 0; 121 | } 122 | 123 | @op(">=", false) inline static public function gte(a:Int32, b:Int32):Bool 124 | { 125 | return Int32.compare(a, b) >= 0; 126 | } 127 | 128 | @op("<", false) inline static public function lt(a:Int32, b:Int32):Bool 129 | { 130 | return Int32.compare(a, b) < 0; 131 | } 132 | 133 | @op("<=", false) inline static public function lte(a:Int32, b:Int32):Bool 134 | { 135 | return Int32.compare(a, b) <= 0; 136 | } 137 | 138 | @op("==", true) inline static public function eq(a:Int32, b:Int32):Bool 139 | { 140 | return Int32.compare(a, b) == 0; 141 | } 142 | 143 | @op("==", true) inline public static function eqInt(a:Int32, b:Int):Bool 144 | { 145 | return Int32.compare(a, Int32.ofInt(b)) == 0; 146 | } 147 | 148 | @op("!=", true) inline static public function neq(a:Int32, b:Int32):Bool 149 | { 150 | return Int32.compare(a, b) != 0; 151 | } 152 | 153 | @op("!=", true) inline public static function neqInt(a:Int32, b:Int):Bool 154 | { 155 | return Int32.compare(a, Int32.ofInt(b)) != 0; 156 | } 157 | 158 | inline static public function abs(a:Int32):Int32 159 | { 160 | if (Int32.isNeg(a)) 161 | return Int32.neg(a); 162 | return a; 163 | } 164 | } -------------------------------------------------------------------------------- /src/test/OverloadTestComplex.hx: -------------------------------------------------------------------------------- 1 | package test; 2 | import deep.macro.math.IOverloadOperator; 3 | import deep.math.Complex; 4 | import deep.math.ComplexMath; 5 | import haxe.unit.TestCase; 6 | 7 | /** 8 | * ... 9 | * @author deep 10 | */ 11 | class A 12 | { 13 | public var a:Complex; 14 | 15 | public var b(getB, setB):Complex; 16 | 17 | private var _b:Complex; 18 | 19 | function getB() { return _b; } 20 | 21 | function setB(v:Complex) { a = v; return _b = v; } 22 | 23 | public function new() 24 | { 25 | a = new Complex(0, 1); 26 | } 27 | } 28 | 29 | enum ComplexRef 30 | { 31 | Ref(c:Complex); 32 | Ref2(c:Complex, b:Complex); 33 | Null; 34 | } 35 | 36 | class OverloadTestComplex extends TestCase, implements IOverloadOperator 37 | { 38 | 39 | public function new() 40 | { 41 | super(); 42 | } 43 | 44 | function test1() 45 | { 46 | var c1 = new Complex(2, 3); 47 | var c2 = new Complex( -4, 1); 48 | var c3; 49 | 50 | c3 = c1 + c2; 51 | 52 | assertTrue(ComplexMath.eq(c3, new Complex( -2, 4))); 53 | } 54 | 55 | function test2() 56 | { 57 | var c:Complex; 58 | 59 | c = new Complex(0, 1); 60 | c *= c; // i^2 61 | 62 | assertTrue(c == new Complex(-1, 0)); 63 | } 64 | 65 | function test3() 66 | { 67 | var c:Complex = new Complex(1, -3.0); 68 | var c2:Complex = new Complex(0, c.re); 69 | c.im = 0; 70 | c /= c2; 71 | 72 | var c3 = c + c2; 73 | 74 | assertTrue(c3 == ComplexMath.add(c, c2)); 75 | } 76 | 77 | function test4() 78 | { 79 | var c = new Complex(0, 10); 80 | var c2:Complex; 81 | 82 | c2 = c; 83 | for (i in 0...Std.int(c.im)) 84 | { 85 | c = c + 0.1; 86 | } 87 | assertTrue(Math.abs(c.re - 1) < 0.00000001); 88 | assertTrue(c != c2); 89 | 90 | c = new Complex(0, 10); 91 | c2 = c; 92 | for (i in 0...Std.int(c.im)) 93 | { 94 | c += 0.1; 95 | } 96 | assertTrue(c == c2); 97 | assertTrue(Math.abs(c.re - 1) < 0.00000001); 98 | } 99 | 100 | function test5() 101 | { 102 | var c = new Complex(0, 1); 103 | 104 | c = ComplexMath.add(new Complex(2, 1), c * c); 105 | 106 | assertTrue(c == new Complex(1, 1)); 107 | 108 | assertTrue( -new Complex(3, -4) == new Complex( -3, 4)); 109 | } 110 | 111 | function test6() 112 | { 113 | var c1 = new Complex(0, 1); 114 | var c2 = new Complex(-3, 4); 115 | var c3 = new Complex(6, -3); 116 | 117 | assertTrue(c1 + c2 * c3 == ComplexMath.add(c1, ComplexMath.mult(c2, c3))); 118 | 119 | assertTrue(c2 * c3 + c1 == ComplexMath.add(c1, ComplexMath.mult(c2, c3))); 120 | 121 | assertTrue(c1 + c2 * c3 == c2 * c3 + c1); 122 | assertTrue(c1 + c2 * c3 == c1 + (c2 * c3)); 123 | assertTrue(c1 + c2 * c3 != (c1 + c2) * c3); 124 | } 125 | 126 | var cR(default, null):Complex; 127 | var cW(null, default):Complex; 128 | var cProp(get_c, set_c):Complex; 129 | var _cProp:Complex; 130 | 131 | function get_c() { return _cProp; } 132 | function set_c(v) { return _cProp = v; } 133 | 134 | function test7() 135 | { 136 | cR = new Complex(0, 1); 137 | var a = [new Complex(1, 2), new Complex(3, 4), null]; 138 | cR *= cR; 139 | 140 | assertTrue(cR == new Complex( -1, 0)); 141 | 142 | cW = cR; 143 | cW += new Complex(1, 1); 144 | 145 | assertTrue(cW == new Complex(0, 1)); 146 | 147 | cProp = cR + cW; 148 | cProp += 1.5; 149 | assertTrue(cProp == _cProp); 150 | 151 | a[2] = a[0] * a[1]; 152 | assertTrue(a[2] == ComplexMath.mult(a[0], a[1])); 153 | } 154 | 155 | function test8() 156 | { 157 | var a:A = new A(); 158 | a.a *= new Complex(0, 1); 159 | assertTrue(a.a == new Complex( -1)); 160 | 161 | a.b = new Complex(1); 162 | 163 | assertTrue(a.a != new Complex( -1)); 164 | assertTrue(a.a == new Complex( 1)); 165 | } 166 | 167 | function test9() 168 | { 169 | 170 | try 171 | { 172 | throw new Complex(1, 2); 173 | } 174 | catch (e:Complex) 175 | { 176 | assertTrue(e + 3.0 == new Complex(4, 2)); 177 | } 178 | catch (d:Dynamic) 179 | { 180 | assertTrue(false); 181 | } 182 | 183 | var r = Ref(new Complex(0, 1)); 184 | switch (r) 185 | { 186 | case Ref(tc): 187 | tc *= tc; 188 | assertTrue(tc == new Complex( -1, 0)); 189 | default: 190 | assertTrue(false); 191 | } 192 | 193 | var d = Ref2(new Complex(1, 0), new Complex(0, 1)); 194 | switch (d) 195 | { 196 | case Ref2(a, b): 197 | assertTrue(a + b == new Complex(1, 1)); 198 | case Ref(a): 199 | assertFalse(true); 200 | default: 201 | assertFalse(true); 202 | } 203 | 204 | switch (d) 205 | { 206 | case Ref2(_, b): 207 | assertTrue(b == new Complex(0, 1)); 208 | case Ref(a): 209 | assertFalse(true); 210 | default: 211 | assertFalse(true); 212 | } 213 | } 214 | 215 | function test10() 216 | { 217 | var a = [new Complex(0, 1), new Complex(1, 1), new Complex(-1, 3)]; 218 | print(a.length); 219 | var s = new Complex(); 220 | 221 | for (c in Lambda.list(a)) 222 | { 223 | s += c; 224 | } 225 | 226 | assertTrue(s == new Complex(0, 5)); 227 | } 228 | 229 | static inline var z:Complex = new Complex(0, 1) + new Complex(1, 0); 230 | 231 | function test11() 232 | { 233 | assertTrue(z == new Complex(1, 1)); 234 | } 235 | 236 | @noOverload function physEq(a:Dynamic, b:Dynamic):Bool 237 | { 238 | return a == b; 239 | } 240 | 241 | function test12() 242 | { 243 | var c = new Complex(1, 2); 244 | var c2 = new Complex(); 245 | c2 <<= c; 246 | var c3 = c; 247 | 248 | assertTrue(c == c3); 249 | assertTrue(physEq(c3, c)); 250 | 251 | assertTrue(c == c2); 252 | assertFalse(physEq(c2, c)); 253 | } 254 | 255 | function test13() 256 | { 257 | var c = new Complex(1, 1); 258 | var c2 = -c; 259 | 260 | assertEquals(1.0, c.re); 261 | assertEquals(1.0, c.im); 262 | assertEquals(-1.0, c2.re); 263 | assertEquals( -1.0, c2.im); 264 | 265 | -c; 266 | assertEquals(1.0, c.re); 267 | assertEquals(1.0, c.im); 268 | } 269 | } -------------------------------------------------------------------------------- /src/deep/math/Int64Math.hx: -------------------------------------------------------------------------------- 1 | package deep.math; 2 | import haxe.Int32; 3 | import haxe.Int64; 4 | 5 | /** 6 | * ... 7 | * @author deep 8 | */ 9 | 10 | class Int64Math 11 | { 12 | 13 | @op("+", true) inline static public var add = Int64.add; 14 | 15 | @op("+", true) inline static public function addInt32(a:Int64, b:Int32):Int64 16 | { 17 | return Int64.add(a, Int64.ofInt32(b)); 18 | } 19 | 20 | @op("+", true) inline static public function addInt(a:Int64, b:Int):Int64 21 | { 22 | return Int64.add(a, Int64.ofInt(b)); 23 | } 24 | 25 | @op("-", true) inline static public var sub = Int64.sub; 26 | 27 | @op("-", false) inline static public function subInt32(a:Int64, b:Int32):Int64 28 | { 29 | return Int64.sub(a, Int64.ofInt32(b)); 30 | } 31 | 32 | @op("-", false) inline static public function subInt(a:Int64, b:Int):Int64 33 | { 34 | return Int64.sub(a, Int64.ofInt(b)); 35 | } 36 | 37 | @op("*", true) inline static public var mult = Int64.mul; 38 | 39 | @op("*", true) inline static public function multInt32(a:Int64, b:Int32):Int64 40 | { 41 | return Int64.mul(a, Int64.ofInt32(b)); 42 | } 43 | 44 | @op("*", true) inline static public function multInt(a:Int64, b:Int):Int64 45 | { 46 | return Int64.mul(a, Int64.ofInt(b)); 47 | } 48 | 49 | @op("/", true) inline static public var div = Int64.div; 50 | 51 | @op("/", false) inline static public function divInt32(a:Int64, b:Int32):Int64 52 | { 53 | return Int64.div(a, Int64.ofInt32(b)); 54 | } 55 | 56 | @op("/", false) inline static public function divInt(a:Int64, b:Int):Int64 57 | { 58 | return Int64.div(a, Int64.ofInt(b)); 59 | } 60 | 61 | @op("%", true) inline static public var mod = Int64.mod; 62 | 63 | @op("%", false) inline static public function modInt32(a:Int64, b:Int32):Int64 64 | { 65 | return Int64.mod(a, Int64.ofInt32(b)); 66 | } 67 | 68 | @op("%", false) inline static public function modInt(a:Int64, b:Int):Int64 69 | { 70 | return Int64.mod(a, Int64.ofInt(b)); 71 | } 72 | 73 | @op("+=", true) inline static public var iadd = Int64.add; 74 | 75 | @op("+=", false) inline static public function iaddInt32(a:Int64, b:Int32):Int64 76 | { 77 | return Int64.add(a, Int64.ofInt32(b)); 78 | } 79 | 80 | @op("+=", false) inline static public function iaddInt(a:Int64, b:Int):Int64 81 | { 82 | return Int64.add(a, Int64.ofInt(b)); 83 | } 84 | 85 | @op("-=", true) inline static public var isub = Int64.sub; 86 | 87 | @op("-=", false) inline static public function isubInt32(a:Int64, b:Int32):Int64 88 | { 89 | return Int64.sub(a, Int64.ofInt32(b)); 90 | } 91 | 92 | @op("-=", false) inline static public function isubInt(a:Int64, b:Int):Int64 93 | { 94 | return Int64.sub(a, Int64.ofInt(b)); 95 | } 96 | 97 | @op("*=", true) inline static public var imult = Int64.mul; 98 | 99 | @op("*=", false) inline static public function imultInt32(a:Int64, b:Int32):Int64 100 | { 101 | return Int64.mul(a, Int64.ofInt32(b)); 102 | } 103 | 104 | @op("*=", false) inline static public function imultInt(a:Int64, b:Int):Int64 105 | { 106 | return Int64.mul(a, Int64.ofInt(b)); 107 | } 108 | 109 | @op("/=", true) inline static public var idiv = Int64.div; 110 | 111 | @op("/=", false) inline static public function idivInt32(a:Int64, b:Int32):Int64 112 | { 113 | return Int64.div(a, Int64.ofInt32(b)); 114 | } 115 | 116 | @op("/=", false) inline static public function idivInt(a:Int64, b:Int):Int64 117 | { 118 | return Int64.div(a, Int64.ofInt(b)); 119 | } 120 | 121 | @op("%=", true) inline static public var imod = Int64.mod; 122 | 123 | @op("%=", false) inline static public function imodInt32(a:Int64, b:Int32):Int64 124 | { 125 | return Int64.mod(a, Int64.ofInt32(b)); 126 | } 127 | 128 | @op("%=", false) inline static public function imodInt(a:Int64, b:Int):Int64 129 | { 130 | return Int64.mod(a, Int64.ofInt(b)); 131 | } 132 | 133 | @op("<<", true) inline static public var shl = Int64.shl; 134 | @op("<<=", true) inline static public var ishl = Int64.shl; 135 | @op(">>", true) inline static public var shr = Int64.shr; 136 | @op(">>=", true) inline static public var ishr = Int64.shr; 137 | @op(">>>", true) inline static public var ushr = Int64.ushr; 138 | @op(">>>=", true) inline static public var iushr = Int64.ushr; 139 | 140 | @op("&", true) inline static public var and = Int64.and; 141 | @op("&=", true) inline static public var iand = Int64.and; 142 | @op("|", true) inline static public var or = Int64.or; 143 | @op("|=", true) inline static public var ior = Int64.or; 144 | @op("^", true) inline static public var xor = Int64.xor; 145 | @op("^=", true) inline static public var ixor = Int64.xor; 146 | 147 | @op("-x") inline static public var neg = Int64.neg; 148 | 149 | @op("++x", false) inline static public function inc(a:Int64):Int64 150 | { 151 | return Int64.add(a, Int64.ofInt(1)); 152 | } 153 | 154 | @op("x++", false) inline static public function pinc(a:Int64):Int64 155 | { 156 | return Int64.add(a, Int64.ofInt(1)); 157 | } 158 | 159 | @op("--x", false) inline static public function dec(a:Int64):Int64 160 | { 161 | return Int64.sub(a, Int64.ofInt(1)); 162 | } 163 | 164 | @op("x--", false) inline static public function pdec(a:Int64):Int64 165 | { 166 | return Int64.sub(a, Int64.ofInt(1)); 167 | } 168 | 169 | @op(">", false) inline static public function gt(a:Int64, b:Int64):Bool 170 | { 171 | return Int64.compare(a, b) > 0; 172 | } 173 | 174 | @op(">=", false) inline static public function gte(a:Int64, b:Int64):Bool 175 | { 176 | return Int64.compare(a, b) >= 0; 177 | } 178 | 179 | @op("<", false) inline static public function lt(a:Int64, b:Int64):Bool 180 | { 181 | return Int64.compare(a, b) < 0; 182 | } 183 | 184 | @op("<=", false) inline static public function lte(a:Int64, b:Int64):Bool 185 | { 186 | return Int64.compare(a, b) <= 0; 187 | } 188 | 189 | @op("==", true) inline static public function eq(a:Int64, b:Int64):Bool 190 | { 191 | return Int64.compare(a, b) == 0; 192 | } 193 | 194 | @op("==", true) inline public static function eqInt32(a:Int64, b:Int32):Bool 195 | { 196 | return Int64.compare(a, Int64.ofInt32(b)) == 0; 197 | } 198 | 199 | @op("==", true) inline public static function eqInt(a:Int64, b:Int):Bool 200 | { 201 | return Int64.compare(a, Int64.ofInt(b)) == 0; 202 | } 203 | 204 | @op("!=", true) inline static public function neq(a:Int64, b:Int64):Bool 205 | { 206 | return Int64.compare(a, b) != 0; 207 | } 208 | 209 | @op("!=", true) inline public static function neqInt32(a:Int64, b:Int32):Bool 210 | { 211 | return Int64.compare(a, Int64.ofInt32(b)) != 0; 212 | } 213 | 214 | @op("!=", true) inline public static function neqInt(a:Int64, b:Int):Bool 215 | { 216 | return Int64.compare(a, Int64.ofInt(b)) != 0; 217 | } 218 | 219 | inline static public function abs(a:Int64):Int64 220 | { 221 | if (Int64.isNeg(a)) 222 | return Int64.neg(a); 223 | return a; 224 | } 225 | 226 | } -------------------------------------------------------------------------------- /src/deep/macro/math/OverloadOperator.hx: -------------------------------------------------------------------------------- 1 | package deep.macro.math; 2 | 3 | #if macro 4 | import haxe.macro.Context; 5 | import haxe.macro.Expr; 6 | #end 7 | 8 | /** 9 | * ... 10 | * @author deep 11 | */ 12 | 13 | class OverloadOperator 14 | { 15 | @:macro public static function addMath(m:ExprRequire>):Expr 16 | { 17 | var type:haxe.macro.Type; 18 | var pos = m.pos; 19 | switch (m.expr) 20 | { 21 | case EConst(c): 22 | switch (c) 23 | { 24 | case CType(s): 25 | type = Context.getType(s); 26 | default: 27 | } 28 | case EType(e, field): 29 | type = Context.getType(field); 30 | 31 | default: 32 | } 33 | if (type == null) Context.error("Math is unknown", pos); 34 | 35 | registerMath(type); 36 | 37 | return {expr:EConst(CIdent("null")), pos:pos}; 38 | } 39 | 40 | #if macro 41 | public static function build():Array 42 | { 43 | registerMath(getDataType(Context.getLocalClass().get())); 44 | 45 | var fields = Context.getBuildFields(); 46 | var nfields = new Array(); 47 | var ctx = []; 48 | 49 | for (f in fields) 50 | { 51 | switch(f.kind) 52 | { 53 | case FVar(t, e): ctx.push( { name:f.name, type:t, expr:null } ); 54 | 55 | case FProp(get, set, t, e): ctx.push( { name:f.name, type:t, expr:null } ); 56 | 57 | case FFun(fn): 58 | var argTypes = Lambda.array(Lambda.map(fn.args, function(arg) return arg.type)); 59 | if (fn.ret != null) 60 | ctx.push( { name:f.name, type:TFunction(argTypes, fn.ret), expr:null } ); 61 | 62 | default: 63 | } 64 | } 65 | 66 | for (f in fields) 67 | { 68 | var ignore = false; 69 | for (m in f.meta) 70 | { 71 | if (m.name == "noOverload") { ignore = true; break; } 72 | } 73 | if (ignore) { nfields.push(f); continue; } 74 | 75 | switch (f.kind) 76 | { 77 | case FVar(t, e): 78 | if (e != null) 79 | f.kind = FieldType.FVar(t, parseExpr(e, ctx.copy())); 80 | nfields.push(f); 81 | 82 | case FProp(get, set, t, e): 83 | if (e != null) 84 | f.kind = FProp(get, set, t, parseExpr(e, ctx.copy())); 85 | nfields.push(f); 86 | 87 | case FFun(fn): 88 | if (fn.expr != null) 89 | { 90 | var nctx = ctx.copy(); 91 | for (arg in fn.args) 92 | { 93 | nctx.push({name:arg.name, type:arg.type, expr:arg.value}); 94 | } 95 | 96 | fn.expr = parseExpr(fn.expr, nctx); 97 | } 98 | nfields.push(f); 99 | 100 | default: 101 | } 102 | } 103 | return nfields; 104 | } 105 | 106 | static function getDataType(cls:haxe.macro.Type.ClassType):haxe.macro.Type 107 | { 108 | for (i in cls.interfaces) 109 | { 110 | if (i.t.get().name == "IOverloadOperator") return i.params[0]; 111 | } 112 | 113 | Context.error("Must implement IOverloadOperator.", Context.currentPos()); 114 | return null; 115 | } 116 | 117 | static var math:Hash; 118 | static var maths:Array; 119 | 120 | static function registerMath(type:haxe.macro.Type) 121 | { 122 | type = Context.follow(type); 123 | var tName = typeName(type); 124 | if (maths == null) 125 | maths = new Array(); 126 | else 127 | if (Lambda.indexOf(maths, tName) != -1) return; 128 | 129 | maths.push(tName); 130 | 131 | var pos = Context.currentPos(); 132 | var typeExp:Expr; 133 | if (math == null) math = new Hash(); 134 | switch (type) 135 | { 136 | case TInst(t, params): 137 | var ct = t.get(); 138 | 139 | for (p in ct.pack) 140 | { 141 | if (typeExp == null) typeExp = { expr:EConst(CIdent(p)), pos:pos }; 142 | else typeExp = { expr:EField(typeExp, p), pos:pos }; 143 | } 144 | typeExp = { expr:EType(typeExp, ct.name), pos:pos }; 145 | 146 | for (method in ct.statics.get()) 147 | { 148 | for (meta in method.meta.get()) 149 | { 150 | if (meta.name != "op") continue; 151 | var param = meta.params[0]; 152 | var o:String = null; 153 | switch (param.expr) 154 | { 155 | case EConst(c): 156 | switch (c) 157 | { 158 | case CString(s): o = s; 159 | default: 160 | } 161 | default: 162 | } 163 | var com = false; 164 | param = meta.params[1]; 165 | if (param != null) 166 | { 167 | switch (param.expr) 168 | { 169 | case EConst(c): 170 | switch (c) 171 | { 172 | case CIdent(i): com = i == "true"; 173 | default: 174 | } 175 | default: 176 | } 177 | } 178 | var ts = new Array(); 179 | switch (Context.follow(method.type)) 180 | { 181 | case TFun(args, ret): 182 | for (a in args) ts.push(typeName(a.t)); 183 | default: 184 | } 185 | var key = o + ":"; 186 | for (t in ts) key += t + "->"; 187 | if (ts.length > 0) key = key.substr(0, key.length - 2); 188 | 189 | var value = { expr:EField(typeExp, method.name), pos:pos }; 190 | if (math.exists(key)) 191 | Context.warning("Overriding existing method " + key, pos); 192 | math.set(key, value); 193 | 194 | if (com && ts.length == 2 && ts[0] != ts[1]) 195 | { 196 | key = "C:" + o + ":"; 197 | ts.reverse(); 198 | for (t in ts) key += t + "->"; 199 | if (ts.length > 0) key = key.substr(0, key.length - 2); 200 | if (math.exists(key)) 201 | Context.warning("Overriding existing method " + key, pos); 202 | math.set(key, value); 203 | } 204 | } 205 | } 206 | default: 207 | } 208 | if (typeExp == null) Context.error("Can't parse math", pos); 209 | } 210 | 211 | static function parseExpr(e:Expr, ctx:IdentDef):Expr 212 | { 213 | if (e == null) return e; 214 | var pos = e.pos; 215 | switch (e.expr) 216 | { 217 | case EConst(c): 218 | return e; 219 | 220 | case EUnop(op, postFix, e1): 221 | var o = defaultOp.get(op); 222 | if (postFix) o = o.substr(-1) + o.substr(0, o.length - 1); 223 | e1 = parseExpr(e1, ctx); 224 | var t1 = typeOf(e1, ctx); 225 | if (t1 == null) Context.error("can't recognize type (EUnop)", e1.pos); 226 | 227 | var key = o + ":" + typeName(t1); 228 | if (math.exists(key)) 229 | { 230 | var call = { expr:ECall( math.get(key), [e1]), pos:pos }; 231 | if (needAssign(o) && canAssign(e1)) return { expr:EBinop(OpAssign, e1, call ), pos:pos }; 232 | else return call; 233 | } 234 | 235 | case EBinop(op, e1, e2): 236 | var assign = false; 237 | switch (op) 238 | { 239 | case OpAssign: 240 | return { expr:EBinop(OpAssign, parseExpr(e1, ctx), parseExpr(e2, ctx)), pos:pos }; 241 | 242 | case OpAssignOp(op2): 243 | assign = true; 244 | op = op2; 245 | default: 246 | } 247 | var o = defaultOp.get(op) + (assign ? "=" : ""); 248 | e1 = parseExpr(e1, ctx); 249 | var t1 = typeOf(e1, ctx); 250 | if (t1 == null) Context.error("can't recognize type (EBinop,1)", e1.pos); 251 | 252 | e2 = parseExpr(e2, ctx); 253 | var t2 = typeOf(e2, ctx); 254 | if (t2 == null) Context.error("can't recognize type (EBinop,2)", e2.pos); 255 | 256 | var key = o + ":" + typeName(t1) + "->" + typeName(t2); 257 | if (math.exists(key)) 258 | { 259 | var call = { expr:ECall( math.get(key), [e1, e2]), pos:pos }; 260 | if (assign && canAssign(e1)) 261 | return { expr:EBinop(OpAssign, e1, call), pos:pos }; 262 | else 263 | return call; 264 | } 265 | else 266 | { 267 | key = "C:" + key; 268 | if (math.exists(key)) 269 | { 270 | var call = { expr:ECall( math.get(key), [e2, e1]), pos:pos }; 271 | if (assign && canAssign(e1)) 272 | return { expr:EBinop(OpAssign, e1, call), pos:pos }; 273 | else 274 | return call; 275 | } 276 | } 277 | 278 | case EParenthesis(e): 279 | return { expr:EParenthesis(parseExpr(e, ctx)), pos:pos }; 280 | 281 | case EBlock(exprs): 282 | var nexprs = new Array(); 283 | var nctx = ctx.copy(); 284 | for (i in exprs) nexprs.push(parseExpr(i, nctx)); 285 | return { expr:EBlock(nexprs), pos:pos }; 286 | 287 | case EArray(e1, e2): 288 | return { expr:EArray(parseExpr(e1, ctx), parseExpr(e2, ctx)), pos:pos }; 289 | 290 | case EArrayDecl(values): 291 | var nvalues = new Array(); 292 | for (i in values) 293 | nvalues.push(parseExpr(i, ctx)); 294 | return { expr:EArrayDecl(nvalues), pos:pos }; 295 | 296 | case EVars(vars): 297 | for (i in vars) 298 | { 299 | i.expr = parseExpr(i.expr, ctx); 300 | ctx.push(i); 301 | } 302 | return { expr:EVars(vars), pos:pos }; 303 | 304 | case EFunction(name, fn): 305 | if (name != null) 306 | { 307 | var argTypes = Lambda.array(Lambda.map(fn.args, function(arg) return arg.type)); 308 | ctx.push( { name:name, type:TFunction(argTypes, fn.ret), expr:null } ); 309 | } 310 | var nctx = ctx.copy(); 311 | for (arg in fn.args) 312 | nctx.push({name:arg.name, type:arg.type, expr:arg.value}); 313 | fn.expr = parseExpr(fn.expr, nctx); 314 | return { expr:EFunction(name, fn), pos:pos }; 315 | 316 | case EUntyped(e): 317 | return { expr:EUntyped(parseExpr(e, ctx)), pos:pos }; 318 | 319 | case ECall(e, params): 320 | var nparams = new Array(); 321 | for (i in params) 322 | nparams.push(parseExpr(i, ctx)); 323 | return { expr:ECall(e, nparams), pos:pos }; 324 | 325 | case ENew(t, params): 326 | var nparams = new Array(); 327 | for (i in params) 328 | nparams.push(parseExpr(i, ctx)); 329 | return { expr:ENew(t, nparams), pos:pos }; 330 | 331 | case EField(e, field): 332 | return { expr:EField(parseExpr(e, ctx), field), pos:pos }; 333 | 334 | case EType(e, field): 335 | return { expr:EType(parseExpr(e, ctx), field), pos:pos }; 336 | 337 | case EObjectDecl(fields): 338 | for (i in fields) i.expr = parseExpr(i.expr, ctx); 339 | return { expr:EObjectDecl(fields), pos:pos }; 340 | 341 | case EIf(econd, eif, eelse): 342 | return { expr:EIf(parseExpr(econd, ctx), parseExpr(eif, ctx), parseExpr(eelse, ctx)), pos:pos }; 343 | 344 | case ETernary(econd, eif, eelse): 345 | return { expr:ETernary(parseExpr(econd, ctx), parseExpr(eif, ctx), parseExpr(eelse, ctx)), pos:pos }; 346 | 347 | case EFor(it, expr): 348 | var idName:String = null; 349 | var nctx = ctx; 350 | switch (it.expr) 351 | { 352 | case EIn(e1, e2): 353 | e1 = parseExpr(e1, ctx); 354 | e2 = parseExpr(e2, ctx); 355 | switch (e1.expr) 356 | { 357 | case EConst(c): 358 | switch (c) 359 | { 360 | case CIdent(id), CType(id): idName = id; 361 | default: 362 | } 363 | default: 364 | } 365 | 366 | if (idName != null) 367 | { 368 | var t = typeOf(e2, ctx); 369 | switch (t) 370 | { 371 | case haxe.macro.Type.TDynamic(t2): t = t2; 372 | case haxe.macro.Type.TMono(t2): t = t2.get(); 373 | case haxe.macro.Type.TFun(_, t2): t = t2; 374 | default: 375 | } 376 | var type:haxe.macro.Type.ClassType; 377 | if (t != null) 378 | { 379 | switch (t) 380 | { 381 | case haxe.macro.Type.TInst(t, params): type = t.get(); 382 | default: 383 | } 384 | if (type != null) 385 | { 386 | for (field in type.fields.get()) 387 | { 388 | if (field.name == "iterator" && field.isPublic) 389 | { 390 | e2 = { expr:ECall( { expr: EField(e2, "iterator"), pos:pos }, []), pos:pos }; 391 | break; 392 | } 393 | } 394 | } 395 | } 396 | nctx = ctx.copy(); 397 | nctx.push( { name:idName, type:null, expr: { expr:ECall( { expr: EField(e2, "next") , pos:pos }, []), pos:pos }} ); 398 | } 399 | default: 400 | } 401 | return { expr:EFor(parseExpr(it, ctx), parseExpr(expr, nctx)), pos:pos }; 402 | 403 | case EWhile(econd, e, normalWhile): 404 | return { expr:EWhile(parseExpr(econd, ctx), parseExpr(e, ctx), normalWhile), pos:pos }; 405 | 406 | case EIn(e1, e2): 407 | return { expr:EIn(parseExpr(e1, ctx), parseExpr(e2, ctx)), pos:pos }; 408 | 409 | case ESwitch(e, cases, edef): 410 | if (edef != null) edef = parseExpr(edef, ctx); 411 | for (c in cases) 412 | { 413 | var nvalues = new Array(); 414 | for (i in c.values) nvalues.push(parseExpr(i, ctx)); 415 | var nctx = ctx; 416 | for (i in nvalues) 417 | { 418 | var types = new Array(); 419 | var ids = new Array(); 420 | switch (i.expr) 421 | { 422 | case ECall(e, params): 423 | switch (Context.follow(Context.typeof(e))) 424 | { 425 | case haxe.macro.Type.TFun(args, t): 426 | for (a in args) types.push(a.t); 427 | default: 428 | 429 | } 430 | if (types.length > 0) 431 | { 432 | for (p in params) 433 | switch (p.expr) 434 | { 435 | case EConst(ec): 436 | switch (ec) 437 | { 438 | case CIdent(t), CType(t): ids.push(t); 439 | default: 440 | } 441 | default: 442 | } 443 | 444 | if (types.length == ids.length) 445 | { 446 | nctx = ctx.copy(); 447 | for (type in types) 448 | { 449 | switch (type) 450 | { 451 | case haxe.macro.Type.TInst(t, params): 452 | var ct = TPath( { sub: null, name: t.get().name, pack: t.get().pack, params: [] } ); 453 | nctx.push( { name:ids.shift(), type:ct, expr:null } ); 454 | 455 | default: nctx.push( { name:ids.shift(), type:null, expr:null } ); 456 | } 457 | } 458 | } 459 | } 460 | 461 | default: 462 | } 463 | } 464 | c.expr = parseExpr(c.expr, nctx); 465 | c.values = nvalues; 466 | } 467 | return { expr:ESwitch(parseExpr(e, ctx), cases, edef), pos:pos }; 468 | 469 | case ETry(e, catches): 470 | for (c in catches) 471 | { 472 | var nctx = ctx.copy(); 473 | nctx.push( { name:c.name, type:c.type, expr:null } ); 474 | c.expr = parseExpr(c.expr, nctx); 475 | } 476 | return { expr:ETry(parseExpr(e, ctx), catches), pos:pos }; 477 | 478 | case EReturn(e): 479 | if (e != null) return { expr:EReturn(parseExpr(e, ctx)), pos:pos }; 480 | 481 | case EThrow(e): 482 | return { expr:EThrow(parseExpr(e, ctx)), pos:pos }; 483 | 484 | case ECast(e, t): 485 | return { expr:ECast(parseExpr(e, ctx), t), pos:pos }; 486 | 487 | default: return e; 488 | } 489 | return e; 490 | } 491 | 492 | static var defaultOp:Map < Dynamic, String > = { 493 | defaultOp = new Map(); 494 | // http://haxe.org/api/haxe/macro/binop 495 | //defaultOp.set(OpAssign, "="); 496 | defaultOp.set(OpAdd, "+"); 497 | defaultOp.set(OpSub, "-"); 498 | defaultOp.set(OpMult, "*"); 499 | defaultOp.set(OpDiv, "/"); 500 | defaultOp.set(OpEq, "=="); 501 | defaultOp.set(OpNotEq, "!="); 502 | defaultOp.set(OpGt, ">"); 503 | defaultOp.set(OpGte, ">="); 504 | defaultOp.set(OpLt, "<"); 505 | defaultOp.set(OpLte, "<="); 506 | defaultOp.set(OpAnd, "&"); 507 | defaultOp.set(OpBoolAnd, "&&"); 508 | defaultOp.set(OpOr, "|"); 509 | defaultOp.set(OpBoolOr, "||"); 510 | defaultOp.set(OpXor, "^"); 511 | defaultOp.set(OpShl, "<<"); 512 | defaultOp.set(OpShr, ">>"); 513 | defaultOp.set(OpUShr, ">>>"); 514 | defaultOp.set(OpMod, "%"); 515 | defaultOp.set(OpInterval, "..."); 516 | 517 | defaultOp.set(OpIncrement, "++x"); // "x++" postfix 518 | defaultOp.set(OpDecrement, "--x"); // "x--" postfix 519 | defaultOp.set(OpNot, "!x"); 520 | defaultOp.set(OpNeg, "-x"); 521 | defaultOp.set(OpNegBits, "~x"); 522 | defaultOp; 523 | } 524 | 525 | static function needAssign(op:String):Bool 526 | { 527 | return op == "++x" || op == "--x" || op == "x++" || op == "x--"; 528 | } 529 | 530 | static function canAssign(e:Expr):Bool 531 | { 532 | switch (e.expr) 533 | { 534 | case EConst(ec): 535 | switch (ec) 536 | { 537 | case CIdent(cid), CType(cid): return true; 538 | default: 539 | } 540 | case EArray(e1, e2): return true; 541 | case EField(e, field): return true; 542 | default: 543 | } 544 | return false; 545 | } 546 | 547 | static function typeName(t:haxe.macro.Type):String 548 | { 549 | t = Context.follow(t); 550 | var type:haxe.macro.Type.BaseType; 551 | switch (t) 552 | { 553 | case TMono(t2): t = t2.get(); 554 | if (t == null) return "null"; 555 | 556 | case TFun(_, ret): t = ret; 557 | 558 | case TDynamic(t2): t = t2; 559 | 560 | default: 561 | } 562 | if (t != null) 563 | switch (t) 564 | { 565 | case TInst(t, _): type = t.get(); 566 | 567 | case TEnum(t, _): type = t.get(); 568 | 569 | case TType(t, _): type = t.get(); 570 | 571 | default: 572 | } 573 | if (type == null) 574 | Context.error("unknown type name '" + t + "'", Context.currentPos()); 575 | 576 | return (type.pack.length > 0 ? type.pack.join(".") + "." : "") + type.name; 577 | } 578 | 579 | static function typeOf(e:Expr, ctx:IdentDef):haxe.macro.Type 580 | { 581 | var t = Context.typeof( { pos:e.pos, expr:EBlock([ { pos:e.pos, expr:EVars(ctx) }, e]) } ); 582 | return Context.follow(t); 583 | } 584 | 585 | #end 586 | } 587 | 588 | #if macro 589 | 590 | class Map 591 | { 592 | var keys:Array; 593 | var values:Array; 594 | 595 | public function new() 596 | { 597 | keys = new Array(); 598 | values = new Array(); 599 | } 600 | 601 | public function set(k:K, v:V) 602 | { 603 | var pos = Lambda.indexOf(keys, k); 604 | if (pos != -1) 605 | { 606 | keys.splice(pos, 1); 607 | values.splice(pos, 1); 608 | } 609 | keys.push(k); 610 | values.push(v); 611 | } 612 | 613 | public function get(k:K):V 614 | { 615 | var pos = Lambda.indexOf(keys, k); 616 | return (pos < 0) ? null : values[pos]; 617 | } 618 | 619 | public function exists(k:K):Bool 620 | { 621 | return Lambda.indexOf(keys, k) > -1; 622 | } 623 | } 624 | 625 | typedef IdentDef = Array<{ name : String, type : Null, expr : Null }>; 626 | 627 | #end --------------------------------------------------------------------------------