package edu.neu.ccs.demeterf.demfgen; import edu.neu.ccs.demeterf.ID; import edu.neu.ccs.demeterf.Control; import edu.neu.ccs.demeterf.util.CLI; import edu.neu.ccs.demeterf.demfgen.classes.*; import edu.neu.ccs.demeterf.demfgen.ClassHier.*; import edu.neu.ccs.demeterf.lib.List; import edu.neu.ccs.demeterf.lib.ident; import java.io.File; /** This class represents the differences between Java and C#, and a few * other DemFGen constants that are useful across Languages. */ public class Diff{ // Date updated frequently: MM/DD/YYYY public static String buildDate = "05/23/2010"; public static boolean isJava(){ return d.isJava(); } public static boolean isCS(){ return d.isCS(); } public static String SEP = File.separator; public static DiffJava d = new DiffJava(); public static void setDiff(DiffJava dd){ d = dd; } /** Option Specs... */ public final static String noparse = "--noparse", noparsecc = "--noparsecc", nogen = "--nogen", noequals = "--noequals", concretes = "--concretes", noshell = "--noshell", mutable = "--mutable", dgp = "--dgp", pcdgp = "--pcdgp", lib = "--lib", build = "--build", graph = "--graph", help = "--help", noctrl = "--nocontrol", parallel = "--parallel", windows = "--windows", showcd = "--show", pubfields = "--publicfields", reference = "--reference", quiet = "--quiet", flatdirs = "--flatdirs", /** New Inlined ClassGen... */ newinlined = "--newinlined", threshhold= "--threshhold"; public final static List validOptions = List.create( noparse,noparsecc,nogen,noequals,concretes,noshell,mutable,dgp,pcdgp,lib, build,graph,help,noctrl,parallel,windows,showcd,pubfields,reference,quiet, newinlined,flatdirs); /** Global access to the options */ static List options; /** Set the global DemFGen Options */ public static void storeOptions(List opt){ options = opt; } /** See if the DemFGen option is set */ public static boolean optionSet(String opt){ return options.contains(opt); } /** Get the ':' separated list attached to the given Optionoption */ public static String[] getOptionList(String opt){ return CLI.separateOption(opt, options); } /** Get a list of DLL references from a command line */ public static String getReferences(){ return List.create(CLI.separateOption(Diff.reference, Diff.options)) .push("DemeterF.dll").toString(" ","-r:"); } /** If C#, then leave the given class name capitalized, for Java we make the first * character lower case to match the normal case */ public static String capName(String s){ return (Diff.isJava()?Character.toLowerCase(s.charAt(0)): Character.toUpperCase(s.charAt(0)))+s.substring(1); } public static class DiffJava{ public String inherit = "extends", fieldClassMod = " static", fieldClassPost = "", fieldImport = ".Fields", pubPriv = "public", protPriv = "protected", fieldImmut = "final", equalsRet = "boolean", equalsMethod = "equals", hashRet = "int", hashMethod = "hashCode", fileSuffix = "java", override = "", toStringMeth = "toString", packageStmt = "package", importStmt = "import", runtimeException = "RuntimeException", stringInput = "java.io.StringReader", inputStream = "java.io.InputStream", inputReader = "java.io.Reader", parserGen = "JavaCC", compilerName = "JavaC", packagePrefix = ";", classEnd= "", basicImport = "", parserImport = importAs("edu.neu.ccs.demeterf","Fields")+ importAs("edu.neu.ccs.demeterf.lib","ident")+ importAs("edu.neu.ccs.demeterf.lib","verbatim"), parserPreamble = Preamble.parserJava, parserBody = Preamble.parserBodyJava, escapeMethods = Preamble.escapeMethodsJava; public char genericSep = '$'; public boolean isJava(){ return true; } public boolean isCS(){ return false; } public List primitives = List.create("byte","short","int","long","float","double", "char","boolean","String","ident","verbatim"); public List boxed = List.create("Byte", "Short", "Integer", "Long", "Float", "Double", "Character", "Boolean","String","ident","verbatim"); public List builtIns = primitives .append(boxed) .append(List.create("ID", "TP", "TU", "FC")); public String unbox(String t){ if(!Diff.d.boxed.contains(t))return t; return Diff.d.primitives.lookup(Diff.d.boxed.index(t)); } public String box(String t){ if(!Diff.d.primitives.contains(t))return t; return Diff.d.boxed.lookup(Diff.d.primitives.index(t)); } public String parseException(String pkg){ return "throws "+pkg+"ParseException"; } public String instanceCheck(String name, String tp){ return " instanceof "+name; } public String classType(String cls, String tp){ return cls+".class"; } public String paramMethod(String meth, String p){ return "<"+box(p)+">"+meth; } public String paramMethodDef(String meth, String ret, String p){ return "<"+box(p)+"> "+ret+" "+meth; } public String varArgs(String t, String arg){ return t+" ... "+arg; } // Separated class/interface inheritance public String extensions(String type, List extnd, List intfc, List params){ String exStr = (extnd.isEmpty()?"":" extends ")+extnd.toString(new InhrtHelp(type,params)), inStr = (intfc.isEmpty()?"":" implements ")+intfc.toString(new InhrtHelp(type,params)); return exStr+inStr; } public String makeParseMsg = " ** Running JavaCC..."; public String makeBuildMsg = " ** Running JavaC..."; public String makeInfo = "Run JavaC after generating the files"; public String importAs(String pkg, String cls){ return importStmt+" "+pkg+"."+cls+";\n"; } public String importAll(String pkg){ return importStmt+" "+pkg+".*;\n"; } public String[] mkParseCmd(String dir){ return new String[]{"bash","-c","javacc -OUTPUT_DIRECTORY=\""+dir+"\" \""+dir+"\"/theparser.jj"}; } public String[] mkParseCmdNoShell(String dir){ return new String[]{"java","javacc","-OUTPUT_DIRECTORY="+dir,dir+SEP+"theparser.jj"}; } static class AddSuff extends List.Map{ String suff; boolean quote; AddSuff(String s, boolean q){ suff = s; quote = q; } public String map(String s){ return "\""+s+"\""+suff; } } public String addSuff(List dirs, String suff, boolean quote){ return dirs.map(new AddSuff(suff,quote)).toString(" ",""); } public String[] buildCmd(List dirs, boolean lib, String name){ return new String[]{"bash","-c","javac "+addSuff(dirs,"/*.java",true)+ (lib?" && jar -cf "+name+" "+addSuff(dirs,"/*.class",true):"")}; } public String[] mkWinParseCmd(String dir){ return new String[]{"java","javacc", "-OUTPUT_DIRECTORY="+dir+"",""+dir+"\\theparser.jj"}; } public String[] buildWinCmd(List dirs, boolean lib, String name){ return new String[]{"cmd","/C","javac "+addSuff(dirs,"\\*.java",false)+ (lib?" && jar -cf "+name+" "+addSuff(dirs,"\\*.class",false):"")}; } public ConstrStr constrStr = new ConstrStr(); public BoundStr bndStr = new BoundStr(); public BoundStr useStr = new UseStr(); public static class ConstrStr extends ID{ String str(TypeDefParams dp){ return ""; } } public static class BoundStr extends ConstrStr{ String combine(NoBound b){ return ""; } String combine(ClassBound b, TypeUse i){ return " extends "+i; } String combine(NameDef d, ident i, String b){ return ""+i+b; } String combine(NameCons c, String i, String e){ return ", "+i+e; } String combine(NENameList c, String i, String e){ return "<"+i+e; } String combine(NameEmpty e){ return ">"; } String combine(DefParams dp, String s){ return s; } String combine(EmptyDefParams e){ return ""; } String str(TypeDefParams dp){ return Factory.newTraversal(this, Control.builtins(TypeUse.class)).traverseTypeDefParams(dp); } } public static class UseStr extends BoundStr{ String combine(ClassBound b, TypeUse i){ return ""; } } } public static class DiffCS extends DiffJava{ public DiffCS(){ inherit = ":"; fieldClassMod = ""; fieldClassPost = "F"; fieldImport = ""; fieldImmut = "readonly"; equalsRet = "bool"; equalsMethod = "Equals"; hashRet = "int"; hashMethod = "GetHashCode"; fileSuffix = "cs"; override = " override"; toStringMeth = "ToString"; packageStmt = "namespace"; importStmt = "using"; runtimeException = "Exception"; stringInput = "System.IO.StringReader"; inputStream = "System.IO.Stream"; inputReader = "System.IO.TextReader"; parserGen = "CSJavaCC"; compilerName = "GMCS"; packagePrefix = "{"; classEnd= "}"; basicImport = importAll("System"); parserImport = importAll("System")+ importAs("edu.neu.ccs.demeterf","Fields")+ importAs("edu.neu.ccs.demeterf.lib","ident")+ importAs("edu.neu.ccs.demeterf.lib","verbatim"); parserPreamble = Preamble.parserCS; parserBody = Preamble.parserBodyCS; escapeMethods = Preamble.escapeMethodsCS; genericSep = '_'; primitives = List.create("byte","short","int","long","float","double", "char","bool","string","ident","verbatim"); boxed = List.create("Byte", "Int16", "Int32", "Int64", "Single", "Double", "Char","Boolean","String","ident","verbatim"); builtIns = primitives .append(boxed) .append(List.create("ID", "TP", "TU", "FC")); makeParseMsg = " ** Running CSJavaCC..."; makeBuildMsg = " ** Running GMCS..."; makeInfo = "Run CSJavaCC & GMCS after generating the files"; constrStr = new CSConstrStr(); bndStr = useStr; } /** Generates the constraints for generaic type bounds */ static class CSConstrStr extends ConstrStr{ NoBound combine(NoBound b){ return b; } String combine(ClassBound b, TypeUse i){ return " : "+i; } String combine(NameDef d, ident i, NoBound b){ return ""; } String combine(NameDef d, ident i, String b){ return "\n where "+i+b; } String combine(NameCons c, String i, String e){ return ""+i+e; } String combine(NENameList c, String i, String e){ return ""+i+e; } String combine(NameEmpty e){ return "\n"; } String combine(DefParams dp, String s){ return s; } String combine(EmptyDefParams e){ return ""; } String str(TypeDefParams dp){ return Factory.newTraversal(this, Control.builtins(TypeUse.class)).traverseTypeDefParams(dp); } } public boolean isJava(){ return false; } public boolean isCS(){ return true; } public String importAs(String pkg, String cls){ return importStmt+" "+cls+" = "+pkg+"."+cls+";\n"; } public String importAll(String pkg){ return importStmt+" "+pkg+";\n"; } public String[] mkParseCmd(String dir){ return new String[]{"bash","-c","java csjavacc -OUTPUT_DIRECTORY=\""+dir+"\" \""+dir+"\"/theparser.jj"}; } public String[] mkParseCmdNoShell(String dir){ return new String[]{"java","csjavacc","-OUTPUT_DIRECTORY="+dir,dir+SEP+"theparser.jj"}; } public String[] buildCmd(List dirs, boolean lib, String name){ String out = (lib?"-out:"+name+" -target:library":"-out:MAIN.exe -target:exe"); return new String[]{"bash","-c","gmcs -warn:1 "+out+" "+Diff.getReferences()+" "+addSuff(dirs,"/*.cs",true)}; } public String[] mkWinParseCmd(String dir){ return new String[]{"cmd","/C","java csjavacc -OUTPUT_DIRECTORY="+dir+" "+dir+"\\theparser.jj"}; } public String[] buildWinCmd(List dirs, boolean lib, String name){ String out = (lib?"/out:"+name+" /target:library":"/out:MAIN.exe /target:exe"); return new String[]{"cmd","/C","csc /warn:1 "+out+" /reference:"+Diff.getReferences()+ " "+addSuff(dirs,"\\*.cs",false)}; } public String box(String t){ return t; } public String parseException(String pkg){ return ""; } public String instanceCheck(String name, String tp){ return " is "+name+tp; } public String classType(String cls, String tp){ return "typeof("+cls+tp+")"; } public String paramMethod(String meth, String p){ return meth+"<"+p+">"; } public String paramMethodDef(String meth, String ret, String p){ return ret+" "+meth+"<"+p+">"; } public String varArgs(String t, String arg){ return "params "+t+"[] "+arg; } // Single list of inheritance... Both a class and possibly multiple interfaces public String extensions(String type, List extnd, List intfc, List params){ List inhrtL = extnd.append(intfc); return ((inhrtL.isEmpty()?"":" : ")+ inhrtL.toString(new InhrtHelp(type, params))); } } static class InhrtHelp extends List.Stringer{ String type; List params; InhrtHelp(String t, List p){ type = t; params = p; } public String toString(InhrtPair ip, List r){ // Extensions need to map the type parameters of the child definition to // the supertype, so that we can correctly rename fields/etc. String pars = (ip.inhrt.extend()?binds(bindingsFromUse(type,ip), params):ip.useParams()); return (ip.inhrt.parent()+pars+(r.isEmpty()?"":", ")); } public String binds(List def, List use){ if(use.isEmpty())return ""; return "<"+use.toString(", ","")+">"; } /** Grab (and check) the matching bindings used for an Extension * like: A(X) = B(X) | C(X). They have to be the same currently. */ public static List bindingsFromUse(final String type, InhrtPair inhrt){ return inhrt.getUParams().map(new List.Map(){ public String map(TypeUse tu){ if(!tu.getTparams().isEmpty()) throw new TE("Type parameters for extensions must be simple bindings."+ "\n Error in definition of: "+type+" with parameter "+tu); return ""+tu.getName(); } }); } /** Rebind the fields based on the child's definition (parameters) and the parents * definition, since type parameters can be renamed in separate definitions. */ public static List rebindFields(String type, List subtpars, InhrtPair inhrt){ List uses = bindingsFromUse(type,inhrt); return DemFGenMain.instantiate(inhrt.fields(), uses, subtpars); } } }