Skip to content

Commit

Permalink
@type metadata added to Flow dsl for static compilers to define abstr…
Browse files Browse the repository at this point in the history
…act fields in the locator class. Refact: Recursive metadata parsing with flow ObjectParser.
  • Loading branch information
FrancisBourre committed Jul 5, 2017
1 parent 49545c6 commit 5f5fddc
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 35 deletions.
6 changes: 5 additions & 1 deletion src/hex/compiletime/basic/StaticCompileTimeContextFactory.hx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ class StaticCompileTimeContextFactory extends CompileTimeContextFactory
this._parseInjectInto( constructorVO );
this._parseMapTypes( constructorVO );

if ( constructorVO.cType != null )
if ( constructorVO.abstractType != null )
{
hex.compiletime.util.ContextBuilder.getInstance( this ).addFieldWithClassName( id, constructorVO.abstractType );
}
else if ( constructorVO.cType != null )
{
hex.compiletime.util.ContextBuilder.getInstance( this ).addField( id, constructorVO.cType );
}
Expand Down
95 changes: 61 additions & 34 deletions src/hex/compiletime/flow/parser/ObjectParser.hx
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ class ObjectParser extends AbstractExprParser<hex.compiletime.basic.BuildRequest
this._runtimeParam = runtimeParam;
}

override public function parse() : Void this._getExpressions().map( this._parseExpression );
override public function parse() : Void this._getExpressions().map( this._parse );
private function _parse( e : Expr ) this._parseExpression( e, new ConstructorVO( '' ) );

private function _parseExpression( e : Expr ) : Void
private function _parseExpression( e : Expr, constructorVO : ConstructorVO ) : Void
{
switch ( e )
{
case macro $i { ident } = $value:
this._builder.build( OBJECT( this._getConstructorVO( ident, value ) ) );
constructorVO.ID = ident;
this._builder.build( OBJECT( this._getConstructorVO( constructorVO, value ) ) );

case macro $i{ident}.$field = $assigned:
var propertyVO = this.parser.parseProperty( this.parser, ident, field, assigned );
Expand All @@ -45,24 +47,33 @@ class ObjectParser extends AbstractExprParser<hex.compiletime.basic.BuildRequest
var args = params.map( function(param) return this.parser.parseArgument(this.parser, ident, param) );
this._builder.build( METHOD_CALL( new MethodCallVO( ident, field, args ) ) );

case macro @inject_into($a{args}) $i{ident} = $value:
var constructorVO = this._getConstructorVO( ident, value );
case macro @inject_into($a { args } ) $e:
constructorVO.injectInto = true;
this._builder.build( OBJECT( constructorVO ) );
this._parseExpression ( e, constructorVO );

case macro @map_type($a{args}) $i{ident} = $value:
var constructorVO = this._getConstructorVO( ident, value );
case macro @map_type( $a{ args } ) $e:
constructorVO.mapTypes = args.map( function( e ) return switch( e.expr )
{
case EConst(CString( mapType )) : mapType;
case _: "";
} );
this._builder.build( OBJECT( constructorVO ) );
this._parseExpression ( e, constructorVO );

case macro @type( $a{ args } ) $e:
constructorVO.abstractType = switch( args[ 0 ].expr )
{
case EConst(CString( abstractType )) : abstractType;
case _: "";
}
this._parseExpression ( e, constructorVO );

case _:

switch( e.expr )
{
case EMeta( meta, e ):
trace( e );

//TODO refactor - Should be part of the property parser
case EBinop( OpAssign, _.expr => EField( ref, field ), value ):
var fields = ExpressionUtil.compressField( ref, field ).split('.');
Expand All @@ -87,48 +98,55 @@ class ObjectParser extends AbstractExprParser<hex.compiletime.basic.BuildRequest
//logger.debug(e);
}

function _getConstructorVO( ident : String, value : Expr ) : ConstructorVO
function _getConstructorVO( constructorVO : ConstructorVO, value : Expr ) : ConstructorVO
{
var constructorVO : ConstructorVO;

switch( value.expr )
{
case EConst(CString(v)):
constructorVO = new ConstructorVO( ident, ContextTypeList.STRING, [ v ] );
constructorVO.type = ContextTypeList.STRING;
constructorVO.arguments = [ v ];

case EConst(CInt(v)):
constructorVO = new ConstructorVO( ident, ContextTypeList.INT, [ v ] );
constructorVO.type = ContextTypeList.INT;
constructorVO.arguments = [ v ];

case EConst(CIdent(v)):

switch( v )
{
case "null":
constructorVO = new ConstructorVO( ident, ContextTypeList.NULL, [ v ] );
constructorVO.type = ContextTypeList.NULL;
constructorVO.arguments = [ v ];

case "true" | "false":
constructorVO = new ConstructorVO( ident, ContextTypeList.BOOLEAN, [ v ] );
constructorVO.type = ContextTypeList.BOOLEAN;
constructorVO.arguments = [ v ];

case _:
var type = hex.preprocess.RuntimeParametersPreprocessor.getType( v, this._runtimeParam );
var arg = new ConstructorVO( ident, (type==null? ContextTypeList.INSTANCE : type), null, null, null, v );
var arg = new ConstructorVO( constructorVO.ID, (type==null? ContextTypeList.INSTANCE : type), null, null, null, v );
arg.filePosition = value.pos;
constructorVO = new ConstructorVO( ident, ContextTypeList.ALIAS, [ arg ], null, null, null, v );

constructorVO.type = ContextTypeList.ALIAS;
constructorVO.arguments = [ arg ];
constructorVO.ref = v;
}

case ENew( t, params ):
constructorVO = this.parser.parseType( this.parser, new ConstructorVO( ident ), value );
this.parser.parseType( this.parser, constructorVO, value );
constructorVO.type = ExprTools.toString( value ).split( 'new ' )[ 1 ].split( '(' )[ 0 ];

case EObjectDecl( fields ):
constructorVO = new ConstructorVO( ident, ContextTypeList.OBJECT, [] );
constructorVO.type = ContextTypeList.OBJECT;
constructorVO.arguments = [];
fields.map( function(field) this._builder.build(
PROPERTY( this.parser.parseProperty( this.parser, ident, field.field, field.expr ) )
PROPERTY( this.parser.parseProperty( this.parser, constructorVO.ID, field.field, field.expr ) )
) );

case EArrayDecl( values ):
constructorVO = new ConstructorVO( ident, ContextTypeList.ARRAY, [] );
values.map( function( e ) constructorVO.arguments.push( this.parser.parseArgument( this.parser, ident, e ) ) );
constructorVO.type = ContextTypeList.ARRAY;
constructorVO.arguments = [];
values.map( function( e ) constructorVO.arguments.push( this.parser.parseArgument( this.parser, constructorVO.ID, e ) ) );

case EField( e, field ):

Expand All @@ -143,15 +161,17 @@ class ObjectParser extends AbstractExprParser<hex.compiletime.basic.BuildRequest
{
case EParenthesis( _.expr => ECheckType( ee, TPath(p) ) ):

constructorVO =
//constructorVO =
if ( p.sub != null )
{
new ConstructorVO( ident, ContextTypeList.STATIC_VARIABLE, [], null, null, false, null, null, className );

constructorVO.type = ContextTypeList.STATIC_VARIABLE;
constructorVO.arguments = [];
constructorVO.staticRef = className;
}
else
{
new ConstructorVO( ident, ContextTypeList.CLASS, [ className ] );
constructorVO.type = ContextTypeList.CLASS;
constructorVO.arguments = [ className];
}

case _:
Expand All @@ -162,15 +182,18 @@ class ObjectParser extends AbstractExprParser<hex.compiletime.basic.BuildRequest
{
//TODO refactor
var type = hex.preprocess.RuntimeParametersPreprocessor.getType( className, this._runtimeParam );
var arg = new ConstructorVO( ident, (type==null? ContextTypeList.INSTANCE : type), null, null, null, className );
var arg = new ConstructorVO( constructorVO.ID, (type==null? ContextTypeList.INSTANCE : type), null, null, null, className );
arg.filePosition = e.pos;
constructorVO = new ConstructorVO( ident, ContextTypeList.ALIAS, [ arg ], null, null, null, className );

constructorVO.type = ContextTypeList.ALIAS;
constructorVO.arguments = [ arg ];
constructorVO.ref = className;
}

case ECall( _.expr => EConst(CIdent(keyword)), params ):
if ( this.parser.buildMethodParser.exists( keyword ) )
{
return this.parser.buildMethodParser.get( keyword )( this.parser, new ConstructorVO( ident ), params, value );
return this.parser.buildMethodParser.get( keyword )( this.parser, constructorVO, params, value );
}
else
{
Expand All @@ -182,7 +205,9 @@ class ObjectParser extends AbstractExprParser<hex.compiletime.basic.BuildRequest
switch( e.expr )
{
case EField( ee, ff ):
constructorVO = new ConstructorVO( ident, ExpressionUtil.compressField( e ), [], null, field );
constructorVO.type = ExpressionUtil.compressField( e );
constructorVO.arguments = [];
constructorVO.staticCall = field;

case ECall( ee, pp ):

Expand All @@ -192,20 +217,22 @@ class ObjectParser extends AbstractExprParser<hex.compiletime.basic.BuildRequest
var factory = field;
var type = a.join( '.' );

constructorVO = new ConstructorVO( ident, type, [], factory, staticCall );
constructorVO.type = type;
constructorVO.arguments = [];
constructorVO.factory = factory;
constructorVO.staticCall = staticCall;

case _:
logger.error( e.expr );
}

if ( params.length > 0 )
{
constructorVO.arguments = params.map( function (e) return this.parser.parseArgument( this.parser, ident, e ) );
constructorVO.arguments = params.map( function (e) return this.parser.parseArgument( this.parser, constructorVO.ID, e ) );
}

case _:
logger.error( value.expr );
constructorVO = new ConstructorVO( ident );
}

constructorVO.filePosition = value.pos;
Expand Down
2 changes: 2 additions & 0 deletions src/hex/vo/ConstructorVO.hx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class ConstructorVO extends AssemblerVO
public var mapTypes : Array<String>;
public var staticRef : String;

public var abstractType : String;

public var shouldAssign = true;

public function new( id : String,
Expand Down
6 changes: 6 additions & 0 deletions test/context/flow/static/abstractTypeField.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@context( name = 'applicationContext' )
{
@type( 'hex.mock.IAnotherMockInterface' )
@map_type( 'hex.mock.IMockInterface' )
test = new hex.mock.MockClass();
}
13 changes: 13 additions & 0 deletions test/hex/compiletime/flow/BasicFlowCompilerTest.hx
Original file line number Diff line number Diff line change
Expand Up @@ -952,4 +952,17 @@ class BasicFlowCompilerTest
this._applicationAssembler = BasicFlowCompiler.compile( "context/flow/arrayConcat.flow" );
Assert.deepEquals( [1,2,3,4,5,6], this._getCoreFactory().locate( "result" ) );
}

@Test( "test abstract typed field with map-type" )
public function testAbstractTypedFieldWithMapType() : Void
{
//We just check here that @type metadata doesn't prevent flow compilation
this._applicationAssembler = BasicFlowCompiler.compile( "context/flow/static/abstractTypeField.flow" );

Assert.isInstanceOf( this._getCoreFactory().locate( "test" ), MockClass );

var map = this._applicationAssembler.getApplicationContext( "applicationContext", ApplicationContext ).getInjector().getInstanceWithClassName( "hex.mock.IMockInterface", "test" );
Assert.isInstanceOf( map, MockClass );
Assert.equals( this._getCoreFactory().locate( "test" ), map );
}
}
24 changes: 24 additions & 0 deletions test/hex/compiletime/flow/BasicStaticFlowCompilerTest.hx
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,14 @@ class BasicStaticFlowCompilerTest
Assert.equals( code.locator.position, code.locator.anotherPosition );
}

@Test( "test Array concat with util" )
public function testArrayConcatWithUtil() : Void
{
var code = BasicStaticFlowCompiler.compile( this._myApplicationAssembler, "context/flow/arrayConcat.flow", "BasicStaticFlowCompiler_testArrayConcatWithUtil" );
code.execute();
Assert.deepEquals( [1,2,3,4,5,6], code.locator.result );
}

@Test( "test Array concat with runtime parameters" )
public function testArrayConcatWithRuntimeParameter() : Void
{
Expand Down Expand Up @@ -1149,5 +1157,21 @@ class BasicStaticFlowCompilerTest
code.execute();
Assert.deepEquals( [ 3, 4 ], code.locator.childContext3.o.owner.collection );
}

@Test( "test abstract typed field with map-type" )
public function testAbstractTypedFieldWithMapType() : Void
{
var applicationAssembler = new ApplicationAssembler();
var code = BasicStaticFlowCompiler.compile( applicationAssembler, "context/flow/static/abstractTypeField.flow", "BasicStaticFlowCompiler_testAbstractTypedFieldWithMapType" );
code.execute();

Assert.isInstanceOf( code.locator.test, MockClass );

var map = code.applicationContext.getInjector().getInstanceWithClassName( "hex.mock.IMockInterface", "test" );
Assert.isInstanceOf( map, MockClass );
Assert.equals( code.locator.test, map );

code.locator.test = new AnotherMockClass();
}
}

0 comments on commit 5f5fddc

Please sign in to comment.