120 likes | 226 Views
Template- und Modellbasierte Codegenerierung für Fujaba. CodeGen2. Beispiel: Einfaches Story Pattern. /** * Describe <code>generateOOCode</code> method here. * * @param methodName a <code>String</code> value * @param incr No description provided
E N D
Template- und Modellbasierte Codegenerierung für Fujaba CodeGen2
/** * Describe <code>generateOOCode</code> method here. * * @param methodName a <code>String</code> value * @param incr No description provided * @param param No description provided * @return an <code>LinkedList[OOStatement]</code> value */ public Object generateCode (FElement incr, String methodName, Object param[]) { String sourceObjectName; String sourceObjectType; String sourceRoleName; String targetObjectName; String targetObjectType; String targetRoleName; String className; boolean targetOptional; boolean targetSet; boolean forEach; boolean sourceQualifierKey; boolean targetQualifierKey; String range; // parse param try { sourceObjectName = (String) param[0]; sourceObjectType = (String) param[1]; sourceRoleName = (String) param[2]; targetObjectName = (String) param[3]; targetObjectType = (String) param[4]; targetRoleName = (String) param[5]; className = (String) param[6]; targetOptional = ((Boolean) param[7]).booleanValue(); targetSet = ((Boolean) param[8]).booleanValue(); forEach = ((Boolean) param[9]).booleanValue(); sourceQualifierKey = ((Boolean) param[10]).booleanValue(); targetQualifierKey = ((Boolean) param[11]).booleanValue(); range = (String) param[12]; } catch (Exception exception) { throw new IllegalArgumentException ("param=" + Arrays.asList (param)); } if (log.isDebugEnabled()) { log.debug (this + ".linkSearchToManyTop(" + "sourceObjectName=" + sourceObjectName + ",sourceObjectType=" + sourceObjectType + ",sourceRoleName=" + sourceRoleName + ",targetObjectName=" + targetObjectName + ",targetObjectType=" + targetObjectType + ",targetRoleName=" + targetRoleName + ",className=" + className + ",targetOptional=" + targetOptional + ",targetSet=" + targetSet + ",forEach=" + forEach + ",sourceQualifierKey=" + sourceQualifierKey + ",targetQualifierKey=" + targetQualifierKey + ",range=" + range); } LinkedList statements = new LinkedList(); OOExpression conditionExpr = null; OOExpression notFujabaSuccess = null; OOCallMethodExpr iteratorMethodExpr = null; OOFWIteratorHasNextExpr hasNextExpr = null; OOCallMethodExpr hasInMethodExpr = null; OOStatement.add (statements, OO.lineComment ("bind " + targetObjectName + ": " + targetObjectType)); String uniqueName = CGU.upFirstChar (sourceObjectName) + CGU.upFirstChar (sourceRoleName) + CGU.upFirstChar (targetObjectName); OOVariable iterName = OO.variable (uniqueName.toString(), OOVariableType.iFujabaIter); iteratorMethodExpr = OO.call (sourceObjectName, OO.method (sourceRoleName, OOMethodType.ITERATOR_OF_METHOD)); if (sourceQualifierKey) { iteratorMethodExpr.addToParameter (OO.identifier (range)); } OOStatement.add (statements, OO.varDecl ("FWIterator", iterName, iteratorMethodExpr)); if (targetOptional) { OOStatement.add (statements, new OODoStatement()); } else { hasNextExpr = OO.iterHasNext (iterName, sourceObjectName, OO.type (sourceRoleName), true); if (!forEach) { notFujabaSuccess = OO.not (OO.identifier (OOVariableType.iFujabaSuccess)); conditionExpr = OO.infixOp (notFujabaSuccess, OOInfixOp.AND_OP, hasNextExpr); } else { conditionExpr = hasNextExpr; } OOStatement.add (statements, OO.whileStat (conditionExpr)); } OOStatement.add (statements, OO.startBlock()); OOStatement.add (statements, new OOTryStatement()); OOStatement.add (statements, OO.startBlock()); if (targetOptional) { OOStatement.add (statements, OO.varDecl (targetObjectType, targetObjectName, OOIdentifierExpr.NULL_IDENTIFIER)); OOStatement.add (statements, OO.ifStat (OO.iterHasNext (iterName, sourceObjectName))); OOStatement.add (statements, OO.startBlock()); } if (targetObjectType.equals (className)) { OOStatement.add (statements, OO.varDecl (targetObjectType, targetObjectName, OO.typeCast (targetObjectType, OO.iterGet (iterName)))); OOStatement.add (statements, OO.exprStat (OO.iterGotoNext (iterName))); OOStatement.add (statements, OO.emptyLine()); } else { OOStatement.add (statements, OO.varDecl (OO.type ("Object"), OO.variable (OOVariableType.iFujabaTmpObject), OO.iterGet (iterName))); if (targetOptional) { OOStatement.add (statements, OO.ifStat (new OOObjectOfTypeExpr (OOVariableType.iFujabaTmpObject, targetObjectType))); OOStatement.add (statements, OO.startBlock()); OOStatement.add (statements, OO.assignStat (targetObjectName, OO.typeCast (targetObjectType, OOVariableType.iFujabaTmpObject))); OOStatement.add (statements, OO.endBlock()); OOStatement.add (statements, new OOElseStatement()); OOStatement.add (statements, OO.startBlock()); OOStatement.add (statements, OO.ensure (OO.not (OO.iterHasNext (iterName, sourceObjectName)))); OOStatement.add (statements, OO.endBlock()); } else { OOStatement.add (statements, OO.ensure (new OOObjectOfTypeExpr (OOVariableType.iFujabaTmpObject, targetObjectType))); OOStatement.add (statements, OO.varDecl (targetObjectType, targetObjectName, OO.typeCast (targetObjectType, OOVariableType.iFujabaTmpObject))); OOStatement.add (statements, OO.emptyLine()); } } if (targetOptional) { OOStatement.add (statements, OO.endBlock()); OOStatement.add (statements, OO.emptyLine()); } if (targetQualifierKey && !sourceQualifierKey) { OOStatement.add (statements, OO.lineComment ("check Reverse-Qualified-Link '" + targetRoleName + "' between " + targetObjectName + " and " + sourceObjectName)); hasInMethodExpr = OO.call (targetObjectName, OO.method (targetRoleName, OOMethodType.HAS_IN_METHOD)); hasInMethodExpr.addToParameter (OO.identifier (range)); hasInMethodExpr.addToParameter (OO.identifier (sourceObjectName)); if (targetOptional) { conditionExpr = OO.infixOp (OO.isNullExpr (targetObjectName), OOInfixOp.OR_OP, hasInMethodExpr); } else { conditionExpr = hasInMethodExpr; } OOStatement.add (statements, OO.ensure (conditionExpr)); OOStatement.add (statements, OO.emptyLine()); } return statements; } OOGenToken Bisher sah das so aus… OOStatement.add (statements, OO.varDecl (OO.type ("Object"), OO.variable (OOVariableType.iFujabaTmpObject), … if (targetOptional) { OOStatement.add (statements, OO.ifStat (new OOObjectOfTypeExpr (OOVariableType.iFujabaTmpObject, … OOStatement.add (statements, OO.startBlock()); OOStatement.add (statements, OO.assignStat (targetObjectName, OO.typeCast (targetObjectType, … OOStatement.add (statements, OO.endBlock()); OOStatement.add (statements, new OOElseStatement()); OOStatement.add (statements, OO.startBlock()); OOStatement.add (statements, OO.ensure (OO.not (OO.iterHasNext (iterName, sourceObjectName)))); OOStatement.add (statements, OO.endBlock()); } else { OOStatement.add (statements, OO.ensure (new OOObjectOfTypeExpr (OOVariableType.iFujabaTmpObject, … OOStatement.add (statements, OO.varDecl (targetObjectType, targetObjectName, OO.typeCast (targetObjectType, … OOStatement.add (statements, OO.emptyLine()); }
Resultat tmp = iterator.next () ; JavaSDM.ensure ( tmp instanceof B ) ; child = (B) tmp ;
Template Code #parse( "storyPattern/link/import.vm" ) #set( $iter = "fujaba__Iter$utility.upFirstChar($sourceName)To$utility.upFirstChar($targetName)" ) // iterate to-many link #if ( $targetSet ) $collectionName = new FHashSet () ; #else fujaba__Success = false ; #end $iter = ${sourceName}.iteratorOf$targetRoleName ($!range) ; while ( #if(!$forEach && !$targetSet)!(fujaba__Success) && #end${iter}.hasNext () ) { try { #set( $source = "#if(!$typeCast)($targetType)#end ${iter}.next ()" ) #set( $toMany = true ) #parse( "storyPattern/object/import.vm" ) $tmpName = $source ; #if ( $typeCast ) // ensure correct type and really bound #if ( $optional && !$toMany ) if ( $tmpName instanceof $type ) { $name = ($type) $tmpName ; } #else JavaSDM.ensure ( $tmpName instanceof $type ) ; $name = ($type) $tmpName ; #end #elseif ( !$optional ) #parse( "storyPattern/object/bound.vm" ) #end $children #if ( $targetSet ) ${collectionName}.add ($targetName); #else fujaba__Success = true ; #end } catch ( JavaSDMException fujaba__InternalException ) { } } #if ( $targetOptional ) if (!fujaba_Success) { fujaba_Success = true ; $targetName = null ; } #end #set( $tmp = "${iter}.next ()" ) #if ( $optional ) if ( $tmpName instanceof $type ) { $name = ($type) $tmp ; } #else JavaSDM.ensure ( $tmp instanceof $type ) ; $name = ($type) $tmp ; #end …und jetzt so!
Konzept • In Fujaba spezifiziert (endlich Bootstrapping!) • Velocity templates
CodeWriting • Velocity Templates • Handler für Tokens • Chain of responsibility Erweiterbar • Einzelne Templates ersetzen • Templatesatz austauschen (z.B. Sprachen) • Tokens einführen (neue Sprachelemente) • Handler ersetzen (Templates wrappen etc.)
Fazit CodeGen2 • Vorteile • Keine Sprachabhängigkeit im Metamodell • Bootstrapping • Neue Sprachen leicht einzuführen • Viel weniger Code / Templates • Nachteile • Noch nicht ganz fertig • Evtl. eingeschränkte Wartbarkeit bei Kopien von Templates