mirror of https://github.com/sbt/sbt.git
Type member support, linearization instead of parents and add inherited members for structure
This commit is contained in:
parent
5662e2a2a6
commit
38dbb1d23c
|
|
@ -27,7 +27,14 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
{
|
||||
override def description = "Extracts the public API from source files."
|
||||
def name = API.name
|
||||
def run: Unit = currentRun.units.foreach(processUnit)
|
||||
def run: Unit =
|
||||
{
|
||||
val start = System.currentTimeMillis
|
||||
if(java.lang.Boolean.getBoolean("sbt.api.enable"))
|
||||
currentRun.units.foreach(processUnit)
|
||||
val stop = System.currentTimeMillis
|
||||
println("API phase took : " + ((stop - start)/1000.0) + " s")
|
||||
}
|
||||
def processUnit(unit: CompilationUnit)
|
||||
{
|
||||
val sourceFile = unit.source.file.file
|
||||
|
|
@ -116,11 +123,39 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
}
|
||||
private def fieldDef[T](s: Symbol, create: (xsbti.api.Type, String, xsbti.api.Access, xsbti.api.Modifiers) => T): T =
|
||||
create(processType(s.tpe), s.fullNameString, getAccess(s), getModifiers(s))
|
||||
private def typeDef(s: Symbol) = error("type members not implemented yet")
|
||||
private def typeDef(s: Symbol): xsbti.api.TypeMember =
|
||||
{
|
||||
val (typeParams, tpe) =
|
||||
s.info match
|
||||
{
|
||||
case PolyType(typeParams0, base) => (typeParameters(typeParams0), base)
|
||||
case t => (Array[xsbti.api.TypeParameter](), t)
|
||||
}
|
||||
val name = s.fullNameString
|
||||
val access = getAccess(s)
|
||||
val modifiers = getModifiers(s)
|
||||
|
||||
private def classStructure(s: Symbol) = structure(s.info.parents, s.info.decls)
|
||||
private def structure(parents: List[Type], defs: Scope) = new xsbti.api.Structure(types(parents), processDefinitions(defs))
|
||||
private def processDefinitions(defs: Scope): Array[xsbti.api.Definition] = defs.toList.toArray.map(definition)
|
||||
if(s.isAliasType)
|
||||
new xsbti.api.TypeAlias(processType(tpe), typeParams, name, access, modifiers)
|
||||
else if(s.isAbstractType)
|
||||
{
|
||||
val bounds = tpe.bounds
|
||||
new xsbti.api.TypeDeclaration(processType(bounds.lo), processType(bounds.hi), typeParams, name, access, modifiers)
|
||||
}
|
||||
else
|
||||
error("Unknown type member" + s)
|
||||
}
|
||||
|
||||
private def structure(s: Symbol): xsbti.api.Structure = structure(s.info)
|
||||
private def structure(info: Type): xsbti.api.Structure =
|
||||
{
|
||||
val s = info.typeSymbol
|
||||
val (declared, inherited) = info.members.partition(_.owner == s)
|
||||
structure(info.baseClasses.map(_.tpe), declared, inherited) // linearization instead of parents
|
||||
}
|
||||
private def structure(parents: List[Type], declared: List[Symbol], inherited: List[Symbol]): xsbti.api.Structure =
|
||||
new xsbti.api.Structure(types(parents), processDefinitions(declared), processDefinitions(inherited))
|
||||
private def processDefinitions(defs: List[Symbol]): Array[xsbti.api.Definition] = defs.toArray.map(definition)
|
||||
private def definition(sym: Symbol): xsbti.api.Definition =
|
||||
{
|
||||
if(sym.isClass) classLike(sym)
|
||||
|
|
@ -133,7 +168,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
{
|
||||
import Flags._
|
||||
new xsbti.api.Modifiers(s.hasFlag(ABSTRACT), s.hasFlag(DEFERRED), s.hasFlag(OVERRIDE),
|
||||
s.isFinal, s.hasFlag(SEALED), isImplicit(s), s.hasFlag(LAZY))
|
||||
s.isFinal, s.hasFlag(SEALED), isImplicit(s), s.hasFlag(LAZY), s.hasFlag(SYNTHETIC))
|
||||
}
|
||||
private def isImplicit(s: Symbol) = s.hasFlag(Flags.IMPLICIT)
|
||||
private def getAccess(c: Symbol): xsbti.api.Access =
|
||||
|
|
@ -164,7 +199,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
if(args.isEmpty) base else new xsbti.api.Parameterized(base, args.map(simpleType).toArray[SimpleType])
|
||||
case SuperType(thistpe: Type, supertpe: Type) => error("Super type (not implemented)")
|
||||
case at: AnnotatedType => annotatedType(at)
|
||||
case RefinedType(parents, defs) => structure(parents, defs)
|
||||
case rt: RefinedType/*(parents, defs)*/ => structure(rt)//parents, defs.toList)
|
||||
case ExistentialType(tparams, result) => new xsbti.api.Existential(processType(result), typeParameters(tparams))
|
||||
case NoType => error("NoType")
|
||||
case PolyType(typeParams, resultType) => println("polyType(" + typeParams + " , " + resultType + ")"); error("polyType")
|
||||
|
|
@ -207,7 +242,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
else DefinitionType.Module
|
||||
}
|
||||
else DefinitionType.ClassDef
|
||||
new xsbti.api.ClassLike(defType, selfType(c), classStructure(c), typeParameters(c), name, access, modifiers)
|
||||
new xsbti.api.ClassLike(defType, selfType(c), structure(c), typeParameters(c), name, access, modifiers)
|
||||
}
|
||||
private final class TopLevelHandler(sourceFile: File) extends TopLevelTraverser
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ Definition
|
|||
TypeAlias
|
||||
tpe: Type
|
||||
TypeDeclaration
|
||||
upperBound: Type
|
||||
lowerBound: Type
|
||||
upperBound: Type
|
||||
|
||||
Type
|
||||
SimpleType
|
||||
|
|
@ -48,6 +48,7 @@ Type
|
|||
Structure
|
||||
parents : Type*
|
||||
declarations: Definition*
|
||||
inherited: Definition*
|
||||
Existential
|
||||
baseType : Type
|
||||
clause: TypeParameter*
|
||||
|
|
@ -74,6 +75,7 @@ Modifiers
|
|||
isSealed: Boolean
|
||||
isImplicit: Boolean
|
||||
isLazy: Boolean
|
||||
isSynthetic: Boolean
|
||||
|
||||
ParameterList
|
||||
parameters: MethodParameter*
|
||||
|
|
|
|||
|
|
@ -34,6 +34,6 @@ public interface AnalysisCallback
|
|||
public void endSource(File sourcePath);
|
||||
/** Called when a module with a public 'main' method with the right signature is found.*/
|
||||
public void foundApplication(File source, String className);
|
||||
|
||||
/** Called when the public API of a source file is extracted. */
|
||||
public void api(File sourceFile, xsbti.api.Source source);
|
||||
}
|
||||
|
|
@ -3,11 +3,23 @@ package xsbt.api
|
|||
import java.io.File
|
||||
import xsbt.FileUtilities
|
||||
|
||||
/** Creates immutable datatype classes in Java from the intermediate Definition representation.
|
||||
*
|
||||
* A ClassDef is written as a class with an optional parent class. The class has a single constructor with
|
||||
* parameters for all declared and inherited members. Declared members are listed first in the constructor.
|
||||
* Inherited members are passed to the super constructor. The value of each member is held in a private
|
||||
* final field and.is accessed by a method of the same name.
|
||||
*
|
||||
* A toString method is generated for debugging.
|
||||
* The classes implement java.io.Serializable.
|
||||
*
|
||||
*.@param baseDirectory output directory for sources
|
||||
* @param pkgName package that classes will be defined in*/
|
||||
class Generator(pkgName: String, baseDirectory: File)
|
||||
{
|
||||
def writeDefinitions(ds: Iterable[Definition]) =
|
||||
{
|
||||
val (nameSet, duplicates) =
|
||||
val (_, duplicates) =
|
||||
( (Set[String](), Set[String]()) /: ds.map(_.name)) {
|
||||
case ((nameSet, duplicates), name) =>
|
||||
if(nameSet.contains(name)) (nameSet, duplicates + name) else (nameSet + name, duplicates)
|
||||
|
|
@ -29,10 +41,11 @@ class Generator(pkgName: String, baseDirectory: File)
|
|||
def write(c: ClassDef): Unit = writeSource(c.name, classContent(c))
|
||||
def classContent(c: ClassDef): String =
|
||||
{
|
||||
val hasParent = c.parent.isDefined
|
||||
val allMembers = c.allMembers.map(normalize)
|
||||
val normalizedMembers = c.members.map(normalize)
|
||||
val fields = normalizedMembers.map(m => "private final " + m.asJavaDeclaration + ";")
|
||||
val accessors = normalizedMembers.map(m => "public final " + m.asJavaDeclaration + "() \n\t{\n\t\treturn " + m.name + ";\n\t}")
|
||||
val accessors = normalizedMembers.map(m => "public final " + m.asJavaDeclaration + "()\n\t{\n\t\treturn " + m.name + ";\n\t}")
|
||||
val parameters = allMembers.map(_.asJavaDeclaration)
|
||||
val assignments = normalizedMembers.map(m => "this." + m.name + " = " + m.name + ";")
|
||||
val superConstructor =
|
||||
|
|
@ -41,23 +54,24 @@ class Generator(pkgName: String, baseDirectory: File)
|
|||
if(inherited.isEmpty) "" else "super(" + inherited.map(_.name).mkString(", ") + ");\n\t\t"
|
||||
}
|
||||
val parametersString = if(allMembers.isEmpty) "\"\"" else allMembers.map(m => fieldToString(m.name, m.single)).mkString(" + \", \" + ")
|
||||
val toStringMethod = "public String toString()\n\t{\n\t\t" +
|
||||
"return \"" + c.name + "(\" + " + parametersString + "+ \")\";\n\t" +
|
||||
"}\n"
|
||||
val toStringMethod = method("public", "String", "toString", "", "\"" + c.name + "(\" + " + parametersString + "+ \")\"")
|
||||
|
||||
val constructor = "public " + c.name + "(" + parameters.mkString(", ") + ")\n\t" +
|
||||
"{\n\t\t" +
|
||||
superConstructor +
|
||||
assignments.mkString("\n\t\t") + "\n\t" +
|
||||
"}"
|
||||
"\nimport java.util.Arrays;\n" +
|
||||
"public class " + c.name + c.parent.map(" extends " + _.name + " ").getOrElse("") + "\n" +
|
||||
"import java.util.Arrays;\n" +
|
||||
"import java.util.List;\n" +
|
||||
"public class " + c.name + c.parent.map(" extends " + _.name + " ").getOrElse(" implements java.io.Serializable") + "\n" +
|
||||
"{\n\t" +
|
||||
constructor + "\n\t" +
|
||||
(fields ++ accessors).mkString("\n\t") + "\n\t" +
|
||||
toStringMethod + "\n" +
|
||||
toStringMethod + "\n\t" +
|
||||
"}"
|
||||
}
|
||||
def method(modifiers: String, returnType: String, name: String, parameters: String, content: String) =
|
||||
modifiers + " " + returnType + " " + name + "(" + parameters + ")\n\t{\n\t\treturn " + content + ";\n\t}"
|
||||
def fieldToString(name: String, single: Boolean) = "\"" + name + ": \" + " + fieldString(name + "()", single)
|
||||
def fieldString(arg: String, single: Boolean) = if(single) arg else "Arrays.toString(" + arg + ")"
|
||||
def normalize(m: MemberDef): MemberDef =
|
||||
|
|
|
|||
Loading…
Reference in New Issue