use File::Copy; use File::Find; use Cwd; # # global variables # # cut the file name of the xpt-file, # e.g. V:/V730/com.atoss.ses.generator/src/main/resources/amf/types/xyz.xpt # at 'resources/' and construct a package name of the remaining parts: # package amf.types $cutPathAt = "resources"; #$cutPathAt = "xpt"; # ATOSS specific imports $atossImports = "import static extension com.atoss.ses.amf.oaw.IncrementalSupport.*\n" . "import static extension com.atoss.ses.amf.oaw.OawExtensionJavaFunctions.*\n"; my $currentDirectory = cwd(); find(\&findFiles, ($currentDirectory)); ################## convert ################################################## # # sub routine, that calls the conversion # # gets the file name of the xpt file as parameter # sub convert { my $xptName = $_[0]; my $xtendName = $xptName; $xptName =~ /\/([^\/]*)\.xpt$/i; my $className = $1; print "converting file $xptName\n"; my @content = &openFile($xptName); # content of the new file my @output = (); # package statement push (@output, &getPackageName ($xptName) . "\n\n"); # some always needed imports # ATOSS related stuff push (@output, $atossImports); # more general imports push (@output, "import com.google.inject.Inject\n"); push (@output, "import org.eclipse.xtext.generator.IFileSystemAccess\n"); # collect all occurences of EXPAND and EXTENSION my @injections = &searchForInjections(@content); my $line = ''; my $isFirstDefine = 0; my $lastWasRootDefine = 0; for ($i = 0; $i < @content; $i++) { $line = $content[$i]; # We are at the first define. Now we have to create a class. # Our rule here is: # if the line contains Root or Start, this # DEFINE is used to add an additional header if ($line =~ /define/i && $isFirstDefine == 0) { $isFirstDefine = 1; push (@output, "class $className\{\n"); # insert the collected injections here push (@output, @injections); if (($line =~ /root/i) || ($line =~ /start/i)) { $lastWasRootDefine = 1; $line =~ /\s+for\s+([^»\s]+)/i; my $type = $1; push (@output, " //line in xpt was $line"); push (@output, " def doGenerate ($type obj, IFileSystemAccess fsa) \{\n"); push (@output, " val fileName = \"TODO\"\n"); push (@output, " val content = main(obj)\n"); push (@output, " fsa.generateFile(fileName, \"TODO\", content)\n"); push (@output, " }\n"); } } # convert define lines to method definitions # for ROOT-definitions: # «DEFINE Root FOR AMFObjectArrayType -» -> # def main (AMFObjectArrayType obj) ''' # for the others: # «DEFINE DAO FOR AMFDbTable » -> # def DAO(AMFDbTable amfdbtable) { if ($line =~ /«define/i) { $line =~ /define\s+(.*?)\s+for\s+([^»\s]+)/i; my $variable = $1; my $type = $2; push (@output, " //line in xpt was $line"); if ($lastWasRootDefine == 1) { push (@output, " def main ($type obj) \'\'\'\n"); } else { push (@output, " def $variable($type " . lc($type). "){\n"); } $line =''; } # EXTENSIONS are already done, nothing to do any longer, they # should be already injected if ($line =~ /«extension/i) { next; } # only keep EXPAND ... FOR lines # the other ones are already treated with the injections if ($line =~ /«expand/i) { unless ($line =~ /for/i) { next; } } # replace ENDDEFINE with } # if the last define was the 'ROOT' Define, # end the ''' section here if ($line =~ /enddefine/i) { if ($lastWasRootDefine == 1) { $lastWasRootDefine = 0; push (@output, " \'\'\'\n"); $line = ''; } else { $line =~ s/«ENDDEFINE»/ \}/; } } # remove suppression of empyt lines: -» -> » $line =~ s/-»/»/; # remove «""-» constructs, also variants like «"" - » are removed $line =~ s/«\"\"\s*-\s*»//; # change import statements: «IMPORT com::atoss::ses::amf» -> import com.atoss.ses.amf.* if ($line =~ /^\s*«import\s+/i) { $line =~ s/«import/import/i; $line =~ s/»/\.\*/i; $line =~ s/::/\./cg; } # remove empty method arguments: hasParamters() -> hasParameters $line =~ s/\(\)//cg; # remove collection casts: «FOREACH (Collection[AMFType])members AS curElem ITERATOR iter -» -> # «FOREACH members AS curElem ITERATOR iter -» $line =~ s/\(Collection\[.*?\]\)//cgi; # blank/remove ENDLET lines if ($line =~ /«endlet/i) { $line = ""; } # LET transformation: «LET getDbTypeConstantFromString(dbType) AS dbTypeInt» -> «val dbTypeInt=getDbTypeConstantFromString(dbType)» if ($line =~ /«let/i) { $line =~ /\s+as\s+([^»\s]+)/i; my $variable = $1; # remove the string ' AS variableName' $line =~ s/as\s+$variable//i; $line =~ s/«let/«val $variable =/i; } # convert expressions like cond ? expr1 : expr2 -> if (cond) expr1 else expr2 if ($line =~ /\?/) { $line =~ s/(\S+)\s*\?\s*(\S+)\s*:\s*(\S+)/if \($1\) $2 else $3/; } # feature call for this: «this.name» -> «obj.name» $line =~ s/«this\./«obj\./i; # feature call for this: «name» -> «obj.name» if ($line =~ /«(\w*)»/) { #check, whether the content between «...» is all in upper case my $tmp = $1; unless ($tmp eq "\U$tmp") { $line =~ s/«$tmp»/«obj\.$tmp»/cg; } } $line =~ s/«name»/«obj\.name»/cg; # «FOREACH complexes AS complex -» -> «FOR complex: obj.complexes » if ($line =~ /«foreach/i) { $line =~ s/«FOREACH/«FOR/; $line =~ /(\S+)\s+AS\s+([^»\s]+)/; my $variable = $2; my $type = $1; # is there a cast before the type? if ($type =~ /^\s*\(/) { $type =~ s/\)/\)obj\./; } else { $type = 'obj.' . $type; } $line =~ s/\S+\s+AS\s+[^»\s]+/$variable : $type/; } # «ENDFOREACH -» -> «ENDFOR -» if ($line =~ /«endforeach/i) { $line =~ s/«ENDFOREACH/«ENDFOR/cg; } # ATOSS specific # Downcast ((AMFSimple) curElem) // nur für AMF* Typen -> (curElem as AMFSimple) while ($line =~ /\(AMF(\w+)\)\s+(\S+)/) { my $variable = $2; my $type = $1; $line =~ s/\(AMF(\w*)\)\s+(\w*)/$variable AS AMF$type/; } # single line comments: «REM» Borrowed from java.lang.Long «ENDREM» -> # //«««Borrowed from java.lang.Long (use both possible types of comments) if ($line =~ /«REM/ && $line =~ /«ENDREM/) { $line =~ s/«REM»/\/\/«««/; $line =~ s/«ENDREM»//; } # EXPAND ... FOREACH # # «EXPAND Stereotype::ImportsForComplexTypesWithFKRelations FOREACH stereotypes -» # -> # «FOR e: obj.stereotypes » # stereotype.ImportsForComplexTypesWithFKRelations(e) # «ENDFOR» # if ($line =~ /expand/i && $line =~ /foreach/i) { $line =~ /expand\s+(\S+?)\s+foreach\s+([^»\s]*)/i; my $variable = $2; my $method = $1; # extract the typeC name from contructs like # typeA::typeB::typeC(this) $method =~ /::([^:]*)$/; $method = $1; # remove possible method parameters at the end # importFkRelations(this) -> importFkRelations $method =~ s/\(.*?\)//; # old line as a comment $line = " //««« line in xpt was: " . &stripLine($line); $line .= " «FOR e: obj\.$variable »\n"; $line .=" $variable\.$method\(e\)\n"; $line .=" «ENDFOR»\n"; } push (@output, $line); } # put a final closing } for the class definition at the end of the output push (@output, "}\n"); $xtendName =~ s/\.xpt$/\.xtend/i; push (@output, "\n\n\n\n/**\n* content of xpt file\n"); foreach $line (@content) { $line = '* ' . $line; } my @complete = (@output, @content); push (@complete, "*/\n"); &writeFile ($xtendName, @complete); } ################## searchForInjections ####################################### # # search for lines, that contain # «EXTENSION amf::base::NameConventions» # «EXPAND ArrayType::ArrayDeclaration # and transform them to # @Inject extension NameConventions # @Inject ArrayType arrayType # sub searchForInjections() { my @content = @_; my @collect = (); foreach my $line (@content) { # «EXTENSION amf::base::NameConventions» # -> # @Inject extension NameConventions # too complicated, does not work, discussed this with dan, # disabled this logic if ($line =~ /«extensionasjfdöalskasdfksdjfösakj/i) { $line =~ /extension\s+([^»\s]*)/i; my $variable = $1; # extract the typeC name from contructs like # typeA::typeB::typeC(this) $variable =~ /::([^:]*)$/; $variable = $1; # remove possible method parameters at the end # importFkRelations(this) -> importFkRelations $variable =~ s/\(.*?\)//; # old line as a comment $line = " //««« line in xpt was: " . &stripLine($line); # different logics for extension and expansions $line .= ' @Inject extension ' . $variable . "\n"; push (@collect, $line); } if ($line =~ /«expand/i) { # only inject expand statements with :: in it unless($line =~ /::/) { next; } # seems to be a for loop, also nothing to interject if ($line =~ /(for|foreach)/i) { next; } # expand lines can contain method calls, don't interpret them als # injections if ($line =~ /\(/i) { next; } $line =~ /expand\s+([^»\s]*)/i; my $variable = $1; # remove the typeC name from contructs like # typeA::typeB::typeC $variable =~ s/::[^:]*$//; # replace :: with . $variable =~ s/::/\./cg; $type = $variable; $variable =~ /\.([^\.]*)$/; $variable = lc ($1); # old line as a comment $line = " //««« line in xpt was: " . &stripLine($line); # different logics for extension and expansions $line .= " \@Inject $type " . $variable . "\n"; push (@collect, $line); } } push (@collect, "\n\n"); return @collect; } ################## getPackageName ############################################# # # try to construct a package name from the path # # cut the path at the variable $cutPathAt, remove the file name and substitute # the path separator with '.' # # e.g. if $cutPathAt is 'xpt' ant the path is s.th. like # V:/convert/xpt/amf/types/root.xpt, the package name would be amf.types # sub getPackageName() { my $packageName = $_[0]; # remove \ with / $packageName =~ s/\\/\//cgi; # does the string contain the $cutPathAt? if ($packageName =~ /$cutPathAt\//i) { # split the string at $cutPathAt $packageName =~ /$cutPathAt\/(.*)/; $packageName = $1; # remove the file name at the end $packageName =~ s/\/([^\/]*)$//; # substitute the '/' with '.' $packageName =~ s/\//\./cg; $packageName = "package " . $packageName; } else { $packageName = "package //TODO enter package name"; } return $packageName; } ################## stripLine ################################################## # # strip a line of '«' and '»' markers # sub stripLine() { my $line = $_[0]; $line =~ s/«//cg; $line =~ s/»//cg; return $line; } ################## findFiles ################################################## # # recursive routine to find all xpt files in the current directory and all # subdirectories # sub findFiles { $name = $File::Find::name; # does the file end with .xpt? unless ($name =~ /\.xpt/i) { return; } # don't touch .svn files if ($name =~ /\.svn/) { return; } &convert($name); } # sub ################## openFile ################################################## # # open file and return the content in an ArrayList # sub openFile { my $filename = $_[0]; my @content = (); unless ( open( FILE, $filename ) ) { print "error during opening $filename, $!\n"; return @content; } @content = ; close(FILE); return @content; } ################## writeFile ################################################## # # 1. Parameter: the file name # 2. Parameter: an arraylist, which contains the content of the file # sub writeFile { my ($filename, @content) = @_; unless (open( FILE, ">$filename")) { print "error during writing $filename, $!\n"; return; } print FILE @content; close(FILE); }