Last active
December 16, 2015 13:39
-
-
Save clemos/5443026 to your computer and use it in GitHub Desktop.
Make haxe switch to accept both patterns and identifiers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import haxe.macro.Context; | |
import haxe.macro.Expr; | |
class HybridSwitch { | |
/* | |
this macro attempts to make switch / case work both | |
with the new pattern matching feature and with | |
simple switch variables | |
it allows to use variables identifiers in cases as well as | |
simple expressions (eg: x+2) or method calls | |
TODO: | |
detect inline variables so they are left as-is | |
*/ | |
macro public static function build( e : Expr ){ | |
switch( e.expr ){ | |
case ESwitch( _ , cases , _ ) : | |
for( c in cases ){ | |
for( v in c.values ){ | |
switch( v.expr ){ | |
case EConst( CIdent( _ ) ), | |
EBinop( _ , _ , _ ), | |
ECall( _ , _ ), | |
EField( _ , _ ) : | |
try{ | |
// check that value exists within scope | |
// otherwise throw "Unknown identifier" | |
Context.typeof( v ); | |
// replace value with __value__ | |
c.values = [{expr:EConst( CIdent( "__value__" ) ), pos:v.pos}]; | |
// add value == switch expr guard | |
var guard = macro __value__ == $v; | |
var userGuard = c.guard; | |
if( userGuard == null ){ | |
c.guard = guard; | |
}else{ | |
c.guard = macro $userGuard && $guard; | |
} | |
}catch( _ : Dynamic ){ | |
// unknown identifier, leave untouched as a pattern | |
} | |
default : | |
// leave as is | |
} | |
} | |
} | |
case _ : | |
Context.error( "Should be switch expression" , Context.currentPos() ); | |
} | |
return e; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyTest { | |
inline static var inlineVar = 5; | |
static var sideEffect; | |
static function toto(){ | |
sideEffect++; | |
return Math.floor( Math.random() * 10 ); | |
} | |
public static function main(){ | |
var a = 5; | |
for(x in 0...10){ | |
HybridSwitch.build( | |
switch(x){ | |
// new guard feature | |
case _ if (x > 6) : trace("superior to 6"); | |
// constant | |
case 1 : trace("ONE"); | |
// variable | |
case a : trace(a); | |
// simple expression | |
case 3 + a : trace(a + " plus three" ); | |
// method call | |
case toto() : trace("toto"); | |
// local inline var | |
case inlineVar : trace("local inline var"); | |
// inline var | |
case Var.inlineVar : trace("inline var"); | |
// static var | |
case Var.notInline : trace("static var"); | |
// match-all pattern | |
case b : trace(b); | |
} | |
); | |
} | |
HybridSwitch.build( | |
switch( MyEnum.Test1( 1 ) ){ | |
case MyEnum.Test1( n ) : trace(n); | |
case MyEnum.Test2( s ) : trace(s); | |
case MyEnum.Test3( MyEnum.Test1( v ) ) : trace(v); | |
default : trace("other pattern"); | |
} | |
); | |
} | |
} | |
enum MyEnum { | |
Test1( t : Int ); | |
Test2( s : String ); | |
Test3( e : MyEnum ); | |
} | |
class Var { | |
public static var notInline = 1; | |
public inline static var inlineVar = 2; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment