Type member support, linearization instead of parents and add inherited members for structure

This commit is contained in:
Mark Harrah 2009-11-22 22:54:17 -05:00
parent 5662e2a2a6
commit 38dbb1d23c
4 changed files with 69 additions and 18 deletions

View File

@ -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
{

View File

@ -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*

View File

@ -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);
}

View File

@ -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 =