Skip to content

Instantly share code, notes, and snippets.

@clemos
Last active December 16, 2015 13:39
Show Gist options
  • Save clemos/5443026 to your computer and use it in GitHub Desktop.
Save clemos/5443026 to your computer and use it in GitHub Desktop.
Make haxe switch to accept both patterns and identifiers
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;
}
}
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