From 5f9f3729d188de656db862d9ed74378dc9ce9c82 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Fri, 22 Jan 2010 20:17:49 -0500 Subject: [PATCH] work on source api parts --- compile/api/APIFormat.scala | 3 +- compile/api/SameAPI.scala | 228 ++++++------- compile/api/ShowAPI.scala | 302 ++++++++++++++++++ compile/api/TagTypeVariables.scala | 137 ++++++++ compile/interface/API.scala | 10 +- interface/definition | 95 ------ interface/other | 68 ++++ interface/type | 27 ++ .../main/resources/sbt/sbt.boot.properties | 2 +- main/AggressiveCompiler.scala | 4 +- main/alt.boot.properties | 2 +- notes | 8 +- project/build/XSbt.scala | 17 +- tasks/standard/Compile.scala | 24 +- util/datatype/GenerateDatatypes.scala | 16 +- util/datatype/Generator.scala | 138 +++++--- 16 files changed, 787 insertions(+), 294 deletions(-) create mode 100644 compile/api/ShowAPI.scala create mode 100644 compile/api/TagTypeVariables.scala create mode 100644 interface/other create mode 100644 interface/type diff --git a/compile/api/APIFormat.scala b/compile/api/APIFormat.scala index 089f26e8f..f420a33e9 100644 --- a/compile/api/APIFormat.scala +++ b/compile/api/APIFormat.scala @@ -29,6 +29,7 @@ object APIFormat try { objIn.readObject().asInstanceOf[Source] } finally { objIn.close() } } - catch { case _: java.io.EOFException | _: java.io.InvalidClassException => new xsbti.api.Source(Array(), Array())} + catch { case _: java.io.EOFException | _: java.io.InvalidClassException => emptySource} } + def emptySource: Source = new Source(Array(), Array()) } \ No newline at end of file diff --git a/compile/api/SameAPI.scala b/compile/api/SameAPI.scala index 4c428bb8f..70d01f78c 100644 --- a/compile/api/SameAPI.scala +++ b/compile/api/SameAPI.scala @@ -1,5 +1,5 @@ /* sbt -- Simple Build Tool - * Copyright 2009 Mark Harrah + * Copyright 2009, 2010 Mark Harrah */ package xsbt.api @@ -13,111 +13,88 @@ object SameAPI def apply(a: Source, b: Source) = { val start = System.currentTimeMillis - val result = (new SameAPI).check(a,b) + + println("\n=========== API #1 ================") + import DefaultShowAPI._ + println(ShowAPI.show(a)) + println("\n=========== API #2 ================") + println(ShowAPI.show(b)) + + val result = (new SameAPI(a,b)).check val end = System.currentTimeMillis println(" API comparison took: " + (end - start) / 1000.0 + " s") result } } -private class SameAPI +private class SameAPI(a: Source, b: Source) { - abstract class Result(val referencesMap: immutable.Map[Int, Int], val parameterMap: immutable.Map[Int, Int]) extends NotNull + private lazy val tagsA = TagTypeVariables(a) + private lazy val tagsB = TagTypeVariables(b) + + def debug(flag: Boolean, msg: => String): Boolean = { - def &&(o: => Result): Result - def value: Boolean - } - final object False extends Result(Map.empty, Map.empty) - { - def &&(o: => Result): Result = this - def value = false - } - final class True(references: immutable.Map[Int, Int], parameters: immutable.Map[Int, Int]) extends Result(references, parameters) - { - def value = true - def &&(o: => Result): Result = o match { case False => o; case t: True => newTrue(t) } - private def newTrue(t: True): True = - { - def equalIntersection(a: Map[Int, Int], b: Map[Int, Int]) = - { - val sameKeys = a.keySet ** b.keySet - assume(sameKeys.forall(key => a(key) == b(key))) - } - equalIntersection(referencesMap, t.referencesMap) - equalIntersection(parameterMap, t.parameterMap) - new True(referencesMap ++ t.referencesMap, parameterMap ++ t.parameterMap) - } - } - implicit def b2b(b: Boolean): Result = if(b) new True(Map.empty, Map.empty) else False - - def debug(flag: Result, msg: => String): Result = - { - if(!flag.value) println(msg) + if(!flag) println(msg) flag } - def printMaps(b: Result) = println(mapStrings(b)) - def mapStrings(b: Result) = + lazy val check: Boolean = { - "parameter map:\n\t" + - b.parameterMap.mkString("\n\t") + - "\nreference map:\n\t" + - b.referencesMap.mkString("\n\t") - } - def check(a: Source, b: Source): Boolean = - { - val initialResult = - samePackages(a, b) && - debug(sameDefinitions(a, b), "Definitions differed") - initialResult.value && - debug(sameReferences(initialResult.referencesMap, initialResult.parameterMap), "References differed: \n" + mapStrings(initialResult)).value + samePackages(a, b) && + debug(sameDefinitions(a, b), "Definitions differed") } - def sameReferences(referencesMap: Map[Int,Int], parameterMap: Map[Int,Int]): Boolean = - referencesMap.forall { case (a, b) => parameterMap(a) == b } - - def samePackages(a: Source, b: Source): Result = + def samePackages(a: Source, b: Source): Boolean = sameStrings(packages(a), packages(b)) def packages(s: Source): Set[String] = Set() ++ s.packages.map(_.name) - def sameDefinitions(a: Source, b: Source): Result = + def sameDefinitions(a: Source, b: Source): Boolean = sameDefinitions(a.definitions, b.definitions) - def sameDefinitions(a: Seq[Definition], b: Seq[Definition]): Result = + def sameDefinitions(a: Seq[Definition], b: Seq[Definition]): Boolean = { - val (avalues, atypes) = separateDefinitions(a) - val (bvalues, btypes) = separateDefinitions(b) + val (avalues, atypes) = separateDefinitions(filterDefinitions(a)) + val (bvalues, btypes) = separateDefinitions(filterDefinitions(b)) debug(sameDefinitions(byName(avalues), byName(bvalues)), "Value definitions differed") && debug(sameDefinitions(byName(atypes), byName(btypes)), "Type definitions differed") } def separateDefinitions(s: Seq[Definition]): (Seq[Definition], Seq[Definition]) = s.toArray.partition(isValueDefinition) - def sameDefinitions(a: scala.collection.Map[String, List[Definition]], b: scala.collection.Map[String, List[Definition]]): Result = - debug(sameStrings(a.keySet, b.keySet), "\tDefinition strings differed") && forall(zippedEntries(a,b))(tupled(sameNamedDefinitions)) + def sameDefinitions(a: scala.collection.Map[String, List[Definition]], b: scala.collection.Map[String, List[Definition]]): Boolean = + debug(sameStrings(a.keySet, b.keySet), "\tDefinition strings differed") && zippedEntries(a,b).forall(tupled(sameNamedDefinitions)) - def sameNamedDefinitions(a: List[Definition], b: List[Definition]): Result = + def filterDefinitions(d: Seq[Definition]) = d.filter(isNonPrivate) + def isNonPrivate(d: Definition): Boolean = isNonPrivate(d.access) + def isNonPrivate(a: Access): Boolean = + a match + { + case p: Private if p.qualifier.isInstanceOf[IdQualifier] => false + case _ => true + } + + def sameNamedDefinitions(a: List[Definition], b: List[Definition]): Boolean = { - println("Comparing " + a.size + " defs against " + b.size + " defs") - def sameDefs(a: List[Definition], b: List[Definition], v: Result): Result = + def show(x: List[Definition]) = x.map(DefaultShowAPI.apply).mkString("{\n\t", "\n\t", "\n}\n") + //println("Comparing \n\t" + show(a) + "\nagainst\n\t" + show(b)) + def sameDefs(a: List[Definition], b: List[Definition]): Boolean = { println("\t " + a.size + " to " + b.size + "") a match { case adef :: atail => - def sameDef(seen: List[Definition], remaining: List[Definition]): Result = + def sameDef(seen: List[Definition], remaining: List[Definition]): Boolean = remaining match { case Nil => debug(false, "Definition different in new API: \n" + adef.name ) case bdef :: btail => - val eq = v && sameDefinitionContent(adef, bdef) - if(eq.value) printMaps(eq) - if(eq.value) sameDefs(atail, seen ::: btail, eq) else sameDef(bdef :: seen, btail) + val eq = sameDefinitionContent(adef, bdef) + if(eq) sameDefs(atail, seen ::: btail) else sameDef(bdef :: seen, btail) } sameDef(Nil, b) - case Nil => v + case Nil => true } } //if(a.length > 1) println("Comparing\n" + a.mkString("\n\t") + "\nagainst\n" + b.mkString("\n\t") + "\n\n") - debug((a.length == b.length), "\t\tLength differed for " + a.headOption.map(_.name).getOrElse("empty")) && sameDefs(a, b, true) + debug((a.length == b.length), "\t\tLength differed for " + a.headOption.map(_.name).getOrElse("empty")) && sameDefs(a, b) } def isValueDefinition(d: Definition): Boolean = @@ -138,14 +115,14 @@ private class SameAPI } // doesn't check name - def sameDefinitionContent(a: Definition, b: Definition): Result = + def sameDefinitionContent(a: Definition, b: Definition): Boolean = //a.name == b.name && debug(sameAccess(a.access, b.access), "Access differed") && debug(sameModifiers(a.modifiers, b.modifiers), "Modifiers differed") && debug(sameAnnotations(a.annotations, b.annotations), "Annotations differed") && debug(sameDefinitionSpecificAPI(a, b), "Definition-specific differed") - def sameAccess(a: Access, b: Access): Result = + def sameAccess(a: Access, b: Access): Boolean = (a, b) match { case (_: Public, _: Public) => true @@ -154,9 +131,9 @@ private class SameAPI case (qa: Pkg, qb: Pkg) => sameQualifier(qa, qb) case _ => debug(false, "Different access categories") } - def sameQualifier(a: Qualified, b: Qualified): Result = + def sameQualifier(a: Qualified, b: Qualified): Boolean = sameQualifier(a.qualifier, b.qualifier) - def sameQualifier(a: Qualifier, b: Qualifier): Result = + def sameQualifier(a: Qualifier, b: Qualifier): Boolean = (a, b) match { case (_: Unqualified, _: Unqualified) => true @@ -165,7 +142,7 @@ private class SameAPI case _ => debug(false, "Different qualifier categories: " + a.getClass.getName + " -- " +b.getClass.getName) } - def sameModifiers(a: Modifiers, b: Modifiers): Result = + def sameModifiers(a: Modifiers, b: Modifiers): Boolean = bitSet(a) == bitSet(b) def bitSet(m: Modifiers): immutable.BitSet = @@ -182,20 +159,20 @@ private class SameAPI setIf(bs, isSynthetic, 7) bs.toImmutable } - def setIf(bs: mutable.BitSet, flag: Result, i: Int): Unit = - if(flag.value) bs += i + def setIf(bs: mutable.BitSet, flag: Boolean, i: Int): Unit = + if(flag) bs += i - def sameAnnotations(a: Seq[Annotation], b: Seq[Annotation]): Result = + def sameAnnotations(a: Seq[Annotation], b: Seq[Annotation]): Boolean = sameSeq(a, b)(sameAnnotation) - def sameAnnotation(a: Annotation, b: Annotation): Result = + def sameAnnotation(a: Annotation, b: Annotation): Boolean = debug(sameSimpleType(a.base, b.base), "Annotation base type differed") && debug(sameAnnotationArguments(a.arguments, b.arguments), "Annotation arguments differed (" + a + ") and (" + b + ")") - def sameAnnotationArguments(a: Seq[AnnotationArgument], b: Seq[AnnotationArgument]): Result = + def sameAnnotationArguments(a: Seq[AnnotationArgument], b: Seq[AnnotationArgument]): Boolean = argumentMap(a) == argumentMap(b) def argumentMap(a: Seq[AnnotationArgument]): Map[String,String] = Map() ++ a.map(arg => (arg.name, arg.value)) - def sameDefinitionSpecificAPI(a: Definition, b: Definition): Result = + def sameDefinitionSpecificAPI(a: Definition, b: Definition): Boolean = (a, b) match { case (fa: FieldLike, fb: FieldLike) => sameFieldSpecificAPI(fa, fb) @@ -203,11 +180,11 @@ private class SameAPI case _ => false } - def sameParameterizedDefinition(a: ParameterizedDefinition, b: ParameterizedDefinition): Result = + def sameParameterizedDefinition(a: ParameterizedDefinition, b: ParameterizedDefinition): Boolean = debug(sameTypeParameters(a.typeParameters, b.typeParameters), "Different type parameters for " + a.name) && sameParameterizedSpecificAPI(a, b) - def sameParameterizedSpecificAPI(a: ParameterizedDefinition, b: ParameterizedDefinition): Result = + def sameParameterizedSpecificAPI(a: ParameterizedDefinition, b: ParameterizedDefinition): Boolean = (a, b) match { case (da: Def, db: Def) => sameDefSpecificAPI(da, db) @@ -217,19 +194,19 @@ private class SameAPI case _ => false } - def sameDefSpecificAPI(a: Def, b: Def): Result = + def sameDefSpecificAPI(a: Def, b: Def): Boolean = debug(sameValueParameters(a.valueParameters, b.valueParameters), "Different def value parameters for " + a.name) && debug(sameType(a.returnType, b.returnType), "Different def return type for " + a.name) - def sameAliasSpecificAPI(a: TypeAlias, b: TypeAlias): Result = + def sameAliasSpecificAPI(a: TypeAlias, b: TypeAlias): Boolean = debug(sameType(a.tpe, b.tpe), "Different alias type for " + a.name) - def sameDeclarationSpecificAPI(a: TypeDeclaration, b: TypeDeclaration): Result = + def sameDeclarationSpecificAPI(a: TypeDeclaration, b: TypeDeclaration): Boolean = debug(sameType(a.lowerBound, b.lowerBound), "Different lower bound for declaration " + a.name) && debug(sameType(a.upperBound, b.upperBound), "Different upper bound for declaration " + a.name) - def sameFieldSpecificAPI(a: FieldLike, b: FieldLike): Result = + def sameFieldSpecificAPI(a: FieldLike, b: FieldLike): Boolean = debug(sameFieldCategory(a, b), "Different field categories (" + a.name + "=" + a.getClass.getName + " -- " +a.name + "=" + a.getClass.getName + ")")&& debug(sameType(a.tpe, b.tpe), "Different field type for " + a.name) - def sameFieldCategory(a: FieldLike, b: FieldLike): Result = + def sameFieldCategory(a: FieldLike, b: FieldLike): Boolean = (a,b) match { case (_: Val, _: Val) => true @@ -237,48 +214,47 @@ private class SameAPI case _=> false } - def sameClassLikeSpecificAPI(a: ClassLike, b: ClassLike): Result = + def sameClassLikeSpecificAPI(a: ClassLike, b: ClassLike): Boolean = sameDefinitionType(a.definitionType, b.definitionType) && sameType(a.selfType, b.selfType) && sameStructure(a.structure, b.structure) - def sameValueParameters(a: Seq[ParameterList], b: Seq[ParameterList]): Result = + def sameValueParameters(a: Seq[ParameterList], b: Seq[ParameterList]): Boolean = sameSeq(a, b)(sameParameterList) - def sameParameterList(a: ParameterList, b: ParameterList): Result = - ((a.isImplicit == b.isImplicit): Result) && + def sameParameterList(a: ParameterList, b: ParameterList): Boolean = + (a.isImplicit == b.isImplicit) && sameParameters(a.parameters, b.parameters) - def sameParameters(a: Seq[MethodParameter], b: Seq[MethodParameter]): Result = + def sameParameters(a: Seq[MethodParameter], b: Seq[MethodParameter]): Boolean = sameSeq(a, b)(sameMethodParameter) - def sameMethodParameter(a: MethodParameter, b: MethodParameter): Result = - ((a.name == b.name): Result) && + def sameMethodParameter(a: MethodParameter, b: MethodParameter): Boolean = + (a.name == b.name) && sameType(a.tpe, b.tpe) && (a.hasDefault == b.hasDefault) && sameParameterModifier(a.modifier, b.modifier) def sameParameterModifier(a: ParameterModifier, b: ParameterModifier) = a == b - def sameDefinitionType(a: DefinitionType, b: DefinitionType): Result = + def sameDefinitionType(a: DefinitionType, b: DefinitionType): Boolean = a == b - def sameVariance(a: Variance, b: Variance): Result = + def sameVariance(a: Variance, b: Variance): Boolean = a == b - def sameTypeParameters(a: Seq[TypeParameter], b: Seq[TypeParameter]): Result = + def sameTypeParameters(a: Seq[TypeParameter], b: Seq[TypeParameter]): Boolean = debug(sameSeq(a, b)(sameTypeParameter), "Different type parameters") - def sameTypeParameter(a: TypeParameter, b: TypeParameter): Result = + def sameTypeParameter(a: TypeParameter, b: TypeParameter): Boolean = sameTypeParameters(a.typeParameters, b.typeParameters) && + debug(sameAnnotations(a.annotations, b.annotations), "Different type parameter annotations") && debug(sameVariance(a.variance, b.variance), "Different variance") && debug(sameType(a.lowerBound, b.lowerBound), "Different lower bound") && debug(sameType(a.upperBound, b.upperBound), "Different upper bound") && - debug(mapSameParameters(a, b), "Different type parameter bindings") + debug(sameTags(a.id, b.id), "Different type parameter bindings") + + def sameTags(a: Int, b: Int): Boolean = tagsA(a) == tagsB(b) - def mapSameParameters(a: TypeParameter, b: TypeParameter): Result = - mapParameters(a.id, b.id) - def mapParameters(a: Int, b: Int) = new True(Map.empty, Map( a -> b )) - - def sameType(a: Type, b: Type): Result = + def sameType(a: Type, b: Type): Boolean = (a, b) match { - case (sa: SimpleType, sb: SimpleType) => debug(sameSimpleType(sa, sb), "Different simple types: " + sa + " and " + {Thread.dumpStack; sb}) + case (sa: SimpleType, sb: SimpleType) => debug(sameSimpleType(sa, sb), "Different simple types: " + DefaultShowAPI(sa) + " and " + DefaultShowAPI(sb)) case (aa: Annotated, ab: Annotated) => debug(sameAnnotatedType(aa, ab), "Different annotated types") case (sa: Structure, sb: Structure) => debug(sameStructure(sa, sb), "Different structure type") case (ea: Existential, eb: Existential) => debug(sameExistentialType(ea, eb), "Different existential type") @@ -286,24 +262,24 @@ private class SameAPI case _ => false } - def sameExistentialType(a: Existential, b: Existential): Result = + def sameExistentialType(a: Existential, b: Existential): Boolean = sameTypeParameters(a.clause, b.clause) && sameType(a.baseType, b.baseType) - def samePolymorphicType(a: Polymorphic, b: Polymorphic): Result = + def samePolymorphicType(a: Polymorphic, b: Polymorphic): Boolean = sameTypeParameters(a.parameters, b.parameters) && sameType(a.baseType, b.baseType) - def sameAnnotatedType(a: Annotated, b: Annotated): Result = + def sameAnnotatedType(a: Annotated, b: Annotated): Boolean = sameSimpleType(a.baseType, b.baseType) && sameAnnotations(a.annotations, b.annotations) - def sameStructure(a: Structure, b: Structure): Result = + def sameStructure(a: Structure, b: Structure): Boolean = sameSeq(a.parents, b.parents)(sameType) && - sameMembers(a.declarations, b.declarations) && + sameMembers(a.declared, b.declared) && sameMembers(a.inherited, b.inherited) - def sameMembers(a: Seq[Definition], b: Seq[Definition]): Result = + def sameMembers(a: Seq[Definition], b: Seq[Definition]): Boolean = sameDefinitions(a, b) - def sameSimpleType(a: SimpleType, b: SimpleType): Result = + def sameSimpleType(a: SimpleType, b: SimpleType): Boolean = (a, b) match { case (pa: Projection, pb: Projection) => debug(sameProjection(pa, pb), "Different projection") @@ -314,23 +290,21 @@ private class SameAPI case _ => debug(false, "Different category of simple type (" + a.getClass.getName + " and " + b.getClass.getName + ") for (" + a + " and " + b + ")") } - def sameParameterized(a: Parameterized, b: Parameterized): Result = + def sameParameterized(a: Parameterized, b: Parameterized): Boolean = sameSimpleType(a.baseType, b.baseType) && sameSeq(a.typeArguments, b.typeArguments)(sameType) - def sameParameterRef(a: ParameterRef, b: ParameterRef): Result = - mapReferences(a.id, b.id) - def mapReferences(a: Int, b: Int) = new True(Map( a -> b ), Map.empty) - def sameSingleton(a: Singleton, b: Singleton): Result = + def sameParameterRef(a: ParameterRef, b: ParameterRef): Boolean = sameTags(a.id, b.id) + def sameSingleton(a: Singleton, b: Singleton): Boolean = samePath(a.path, b.path) - def sameProjection(a: Projection, b: Projection): Result = + def sameProjection(a: Projection, b: Projection): Boolean = sameSimpleType(a.prefix, b.prefix) && (a.id == b.id) - def samePath(a: Path, b: Path): Result = + def samePath(a: Path, b: Path): Boolean = samePathComponents(a.components, b.components) - def samePathComponents(a: Seq[PathComponent], b: Seq[PathComponent]): Result = + def samePathComponents(a: Seq[PathComponent], b: Seq[PathComponent]): Boolean = sameSeq(a, b)(samePathComponent) - def samePathComponent(a: PathComponent, b: PathComponent): Result = + def samePathComponent(a: PathComponent, b: PathComponent): Boolean = (a, b) match { case (_: This, _: This) => true @@ -338,25 +312,19 @@ private class SameAPI case (ia: Id, ib: Id) => samePathId(ia, ib) case _ => false } - def samePathSuper(a: Super, b: Super): Result = + def samePathSuper(a: Super, b: Super): Boolean = samePath(a.qualifier, b.qualifier) - def samePathId(a: Id, b: Id): Result = + def samePathId(a: Id, b: Id): Boolean = a.id == b.id // precondition: a.keySet == b.keySet protected def zippedEntries[A,B](a: scala.collection.Map[A,B], b: scala.collection.Map[A,B]): Iterable[(B,B)] = for( (key, avalue) <- a) yield (avalue, b(key)) - def sameStrings(a: scala.collection.Set[String], b: scala.collection.Set[String]): Result = + def sameStrings(a: scala.collection.Set[String], b: scala.collection.Set[String]): Boolean = a == b - final def sameSeq[T](a: Seq[T], b: Seq[T])(eq: (T,T) => Result): Result = + final def sameSeq[T](a: Seq[T], b: Seq[T])(eq: (T,T) => Boolean): Boolean = sameArray(a.toArray, b.toArray)(eq) - final def sameArray[T](a: Array[T], b: Array[T])(eq: (T,T) => Result): Result = - ((a.length == b.length): Result) && forall(a.zip(b))(tupled(eq)) - final def forall[T](a: Iterable[T])(f: T => Result): Result = forallList(a.toList, true)(f) - final def forallList[T](a: List[T], v: Result)(f: T => Result): Result = - if(v.value) ( a match { case Nil => v; case x :: xs => forallList(xs, v && f(x) )(f) } ) - else v - - def defaultEquals[T <: AnyRef] = (a: T, b: T) => a == b + final def sameArray[T](a: Array[T], b: Array[T])(eq: (T,T) => Boolean): Boolean = + (a.length == b.length) && (a zip b).forall(tupled(eq)) } \ No newline at end of file diff --git a/compile/api/ShowAPI.scala b/compile/api/ShowAPI.scala new file mode 100644 index 000000000..405e86cbb --- /dev/null +++ b/compile/api/ShowAPI.scala @@ -0,0 +1,302 @@ +/* sbt -- Simple Build Tool + * Copyright 2010 Mark Harrah + */ +package xsbt.api + +import xsbti.api._ + +trait Show[A] +{ + def show(a: A): String +} + +final class ShowLazy[A](delegate: => Show[A]) extends Show[A] +{ + private lazy val s = delegate + def show(a: A) = s.show(a) +} + +import ShowAPI._ + +object ShowAPI +{ + def Show[T](implicit s: Show[T]): Show[T] = s + def show[T](t: T)(implicit s: Show[T]): String = s.show(t) + + def bounds(lower: Type, upper: Type)(implicit t: Show[Type]): String = + ">: " + t.show(lower) + " <: " + t.show(upper) + + import ParameterModifier._ + def parameterModifier(base: String, pm: ParameterModifier): String = + pm match + { + case Plain => base + case Repeated => base + "*" + case ByName => "=> " + base + } + + def concat[A](list: Seq[A], as: Show[A], sep: String): String = mapSeq(list, as).mkString(sep) + def commas[A](list: Seq[A], as: Show[A]): String = concat(list, as, ", ") + def spaced[A](list: Seq[A], as: Show[A]): String = concat(list, as, " ") + def lines[A](list: Seq[A], as: Show[A]): String = mapSeq(list, as).mkString("", "\n", "\n") + def mapSeq[A](list: Seq[A], as: Show[A]): Seq[String] = list.map(as.show) +} + +trait ShowBase +{ + implicit def showAnnotation(implicit as: Show[AnnotationArgument], t: Show[Type]): Show[Annotation] = + new Show[Annotation] { def show(a: Annotation) = "@" + t.show(a.base) + (if(a.arguments.isEmpty) "" else "(" + commas(a.arguments, as) + ")") } + + implicit def showAnnotationArgument: Show[AnnotationArgument] = + new Show[AnnotationArgument] { def show(a: AnnotationArgument) = a.name + " = " + a.value } + + import Variance._ + implicit def showVariance: Show[Variance] = + new Show[Variance] { def show(v: Variance) = v match { case Invariant => ""; case Covariant => "+"; case Contravariant => "-" } } + + implicit def showSource(implicit ps: Show[Package], ds: Show[Definition]): Show[Source] = + new Show[Source] { def show(a: Source) = lines(a.packages, ps) + lines(a.definitions, ds) } + + implicit def showPackage: Show[Package] = + new Show[Package] { def show(pkg: Package) = "package " + pkg.name } + + implicit def showAccess(implicit sq: Show[Qualified]): Show[Access] = + new Show[Access] + { + def show(a: Access) = + a match + { + case p: Public => "public" + case q: Qualified => sq.show(q) + } + } + implicit def showQualified(implicit sq: Show[Qualifier]): Show[Qualified] = + new Show[Qualified] + { + def show(q: Qualified) = + ((q match + { + case p: Protected => "protected" + case p: Private => "private" + case p: Pkg => "package" + }) + + sq.show(q.qualifier) ) + } + implicit def showQualifier: Show[Qualifier] = + new Show[Qualifier] + { + def show(q: Qualifier) = + q match + { + case _: Unqualified => "" + case _: ThisQualifier => "[this]" + case i: IdQualifier => "[" + i.value + "]" + } + } + implicit def showModifiers: Show[Modifiers] = + new Show[Modifiers] + { + def show(m: Modifiers) = + { + val mods = + (m.isOverride, "override") :: + (m.isFinal, "final") :: + (m.isSealed, "sealed") :: + (m.isImplicit, "implicit") :: + (m.isAbstract || m.isDeferred, "abstract") :: + (m.isLazy, "lazy") :: + (m.isSynthetic, "synthetic") :: + Nil + mods.filter(_._1).map(_._2).mkString(" ") + } + } + + implicit def showDefinitionType: Show[DefinitionType] = + new Show[DefinitionType] { + import DefinitionType._ + def show(dt: DefinitionType) = + dt match + { + case Trait => "trait" + case ClassDef => "class" + case Module => "object" + case PackageModule => "package object" + } + } +} +trait ShowDefinitions +{ + implicit def showVal(implicit acs: Show[Access], ms: Show[Modifiers], ans: Show[Annotation], t: Show[Type]): Show[Val] = + new Show[Val] { def show(v: Val) = definitionBase(v, "val")(acs, ms, ans) + ": " + t.show(v.tpe) } + + implicit def showVar(implicit acs: Show[Access], ms: Show[Modifiers], ans: Show[Annotation], t: Show[Type]): Show[Var] = + new Show[Var] { def show(v: Var) = definitionBase(v, "var")(acs, ms, ans) + ": " + t.show(v.tpe) } + + implicit def showDef(implicit acs: Show[Access], ms: Show[Modifiers], ans: Show[Annotation], tp: Show[Seq[TypeParameter]], vp: Show[Seq[ParameterList]], t: Show[Type]): Show[Def] = + new Show[Def] { def show(d: Def) = parameterizedDef(d, "def")(acs, ms, ans, tp) + vp.show(d.valueParameters) + ": " + t.show(d.returnType) } + + implicit def showClassLike(implicit acs: Show[Access], ms: Show[Modifiers], ans: Show[Annotation], tp: Show[Seq[TypeParameter]], dt: Show[DefinitionType], s: Show[Structure], t: Show[Type]): Show[ClassLike] = + new Show[ClassLike] { def show(cl: ClassLike) = parameterizedDef(cl, dt.show(cl.definitionType))(acs, ms, ans, tp) + " requires " + t.show(cl.selfType) + " extends " + s.show(cl.structure) } + + implicit def showTypeAlias(implicit acs: Show[Access], ms: Show[Modifiers], ans: Show[Annotation], tp: Show[Seq[TypeParameter]], t: Show[Type]): Show[TypeAlias] = + new Show[TypeAlias] { def show(ta: TypeAlias) = parameterizedDef(ta, "type")(acs, ms, ans, tp) + " = " + t.show(ta.tpe) } + + implicit def showTypeDeclaration(implicit acs: Show[Access], ms: Show[Modifiers], ans: Show[Annotation], tp: Show[Seq[TypeParameter]], t: Show[Type]): Show[TypeDeclaration] = + new Show[TypeDeclaration] { def show(td: TypeDeclaration) = parameterizedDef(td, "type")(acs, ms, ans, tp) + bounds(td.lowerBound, td.upperBound) } + + def parameterizedDef(d: ParameterizedDefinition, label: String)(implicit acs: Show[Access], ms: Show[Modifiers], ans: Show[Annotation], tp: Show[Seq[TypeParameter]]): String = + definitionBase(d, label)(acs, ms, ans) + tp.show(d.typeParameters) + def definitionBase(d: Definition, label: String)(implicit acs: Show[Access], ms: Show[Modifiers], ans: Show[Annotation]): String = + spaced(d.annotations, ans) + " " + acs.show(d.access) + " " + ms.show(d.modifiers) + " " + label + " " + d.name +} +trait ShowDefinition +{ + implicit def showDefinition(implicit vl: Show[Val], vr: Show[Var], ds: Show[Def], cl: Show[ClassLike], ta: Show[TypeAlias], td: Show[TypeDeclaration]): Show[Definition] = + new Show[Definition] + { + def show(d: Definition) = + d match + { + case v: Val => vl.show(v) + case v: Var => vr.show(v) + case d: Def => ds.show(d) + case c: ClassLike => cl.show(c) + case t: TypeAlias => ta.show(t) + case t: TypeDeclaration => td.show(t) + } + } +} +trait ShowType +{ + implicit def showType(implicit s: Show[SimpleType], a: Show[Annotated], st: Show[Structure], e: Show[Existential], po: Show[Polymorphic]): Show[Type] = + new Show[Type] + { + def show(t: Type) = + t match + { + case q: SimpleType => s.show(q) + case q: Annotated => a.show(q) + case q: Structure => st.show(q) + case q: Existential => e.show(q) + case q: Polymorphic => po.show(q) + } + } + + implicit def showSimpleType(implicit pr: Show[Projection], pa: Show[ParameterRef], si: Show[Singleton], et: Show[EmptyType], p: Show[Parameterized]): Show[SimpleType] = + new Show[SimpleType] { + def show(t: SimpleType) = + t match + { + case q: Projection => pr.show(q) + case q: ParameterRef => pa.show(q) + case q: Singleton => si.show(q) + case q: EmptyType => et.show(q) + case q: Parameterized => p.show(q) + } + } +} +trait ShowBasicTypes +{ + implicit def showSingleton(implicit p: Show[Path]): Show[Singleton] = + new Show[Singleton] { def show(s: Singleton) = p.show(s.path) } + implicit def showEmptyType: Show[EmptyType] = + new Show[EmptyType] { def show(e: EmptyType) = "" } + implicit def showParameterRef: Show[ParameterRef] = + new Show[ParameterRef] { def show(p: ParameterRef) = "<" + p.id + ">" } +} +trait ShowTypes +{ + implicit def showStructure(implicit t: Show[Type], d: Show[Definition]): Show[Structure] = + new Show[Structure] { + def show(s: Structure) = + concat(s.parents, t, " with ") + "\n{\n\tDeclared:" + lines(s.declared, d) + "\n\tInherited:" + lines(s.inherited, d) + "\n}" + } + implicit def showAnnotated(implicit as: Show[Annotation], t: Show[SimpleType]): Show[Annotated] = + new Show[Annotated] { def show(a: Annotated) = spaced(a.annotations, as) + " " + t.show(a.baseType) } + implicit def showProjection(implicit t: Show[SimpleType]): Show[Projection] = + new Show[Projection] { def show(p: Projection) = t.show(p.prefix) + "#" + p.id } + implicit def showParameterized(implicit t: Show[Type]): Show[Parameterized] = + new Show[Parameterized] { def show(p: Parameterized) = t.show(p.baseType) + mapSeq(p.typeArguments, t).mkString("[", ", ", "]") } + implicit def showExistential(implicit t: Show[Type], tp: Show[TypeParameter]): Show[Existential] = + new Show[Existential] { + def show(e: Existential) = + t.show(e.baseType) + e.clause.map(t => "type " + tp.show(t)).mkString(" forSome { ", "; ", "}") + } + implicit def showPolymorphic(implicit t: Show[Type], tps: Show[Seq[TypeParameter]]): Show[Polymorphic] = + new Show[Polymorphic] { def show(p: Polymorphic) = t.show(p.baseType) + tps.show(p.parameters) } + +} + +trait ShowPath +{ + implicit def showPath(implicit pc: Show[PathComponent]): Show[Path] = + new Show[Path] { def show(p: Path) = mapSeq(p.components, pc).mkString(".") } + + implicit def showPathComponent(implicit sp: Show[Path]): Show[PathComponent] = + new Show[PathComponent] { + def show(p: PathComponent) = + p match + { + case s: Super => "super[" + sp.show(s.qualifier) + "]" + case _: This => "this" + case i: Id => i.id + } + } +} + +trait ShowValueParameters +{ + implicit def showParameterLists(implicit pl: Show[ParameterList]): Show[Seq[ParameterList]] = + new Show[Seq[ParameterList]] { def show(p: Seq[ParameterList]) = concat(p,pl, "") } + implicit def showParameterList(implicit mp: Show[MethodParameter]): Show[ParameterList] = + new Show[ParameterList] { def show(pl: ParameterList) = "(" + (if(pl.isImplicit) "implicit " else "") + commas(pl.parameters, mp) + ")" } + + implicit def showMethodParameter(implicit t: Show[Type]): Show[MethodParameter] = + new Show[MethodParameter] { + def show(mp: MethodParameter) = + mp.name + ": " + parameterModifier(t.show(mp.tpe), mp.modifier) + (if(mp.hasDefault) "= ..." else "") + } +} +trait ShowTypeParameters +{ + implicit def showTypeParameters(implicit as: Show[TypeParameter]): Show[Seq[TypeParameter]] = + new Show[Seq[TypeParameter]] { def show(tps: Seq[TypeParameter]) = if(tps.isEmpty) "" else mapSeq(tps, as).mkString("[", ",", "]") } + implicit def showTypeParameter(implicit as: Show[Annotation], tp: Show[Seq[TypeParameter]], t: Show[Type], v: Show[Variance]): Show[TypeParameter] = + new Show[TypeParameter] { + def show(tps: TypeParameter) = + spaced(tps.annotations, as) + " " + v.show(tps.variance) + tps.id + tp.show(tps.typeParameters) + " " + bounds(tps.lowerBound, tps.upperBound) + } +} + +object DefaultShowAPI extends ShowBase with ShowBasicTypes with ShowValueParameters +{ + def apply(d: Definition) = ShowAPI.show(d) + def apply(d: Type) = ShowAPI.show(d) + + implicit lazy val showVal: Show[Val] = Cyclic.showVal + implicit lazy val showVar: Show[Var] = Cyclic.showVar + implicit lazy val showClassLike: Show[ClassLike] = Cyclic.showClassLike + implicit lazy val showTypeDeclaration: Show[TypeDeclaration] = Cyclic.showTypeDeclaration + implicit lazy val showTypeAlias: Show[TypeAlias] = Cyclic.showTypeAlias + implicit lazy val showDef: Show[Def] = Cyclic.showDef + + implicit lazy val showProj: Show[Projection] = Cyclic.showProjection + implicit lazy val showPoly: Show[Polymorphic] = Cyclic.showPolymorphic + + implicit lazy val showSimple: Show[SimpleType] = new ShowLazy(Cyclic.showSimpleType) + implicit lazy val showAnnotated: Show[Annotated] = Cyclic.showAnnotated + implicit lazy val showExistential: Show[Existential] = Cyclic.showExistential + implicit lazy val showParameterized: Show[Parameterized] = Cyclic.showParameterized + + implicit lazy val showTypeParameters: Show[Seq[TypeParameter]] = new ShowLazy(Cyclic.showTypeParameters) + implicit lazy val showTypeParameter: Show[TypeParameter] = Cyclic.showTypeParameter + + implicit lazy val showDefinition: Show[Definition] = new ShowLazy(Cyclic.showDefinition) + implicit lazy val showType: Show[Type] = new ShowLazy(Cyclic.showType) + implicit lazy val showStructure: Show[Structure] = new ShowLazy(Cyclic.showStructure) + + implicit lazy val showPath: Show[Path] = new ShowLazy(Cyclic.showPath) + implicit lazy val showPathComponent: Show[PathComponent] = Cyclic.showPathComponent + + private object Cyclic extends ShowTypes with ShowType with ShowPath with ShowDefinition with ShowDefinitions with ShowTypeParameters +} \ No newline at end of file diff --git a/compile/api/TagTypeVariables.scala b/compile/api/TagTypeVariables.scala new file mode 100644 index 000000000..23763a4f3 --- /dev/null +++ b/compile/api/TagTypeVariables.scala @@ -0,0 +1,137 @@ +package xsbt.api + +import xsbti.api._ + +object TagTypeVariables +{ + def apply(s: Source): scala.collection.Map[Int, (Int, Int)] = (new TagTypeVariables).tag(s) +} +private class TagTypeVariables extends NotNull +{ + private val tags = new scala.collection.mutable.HashMap[Int, (Int, Int)] + private var level = 0 + private var index = 0 + + def tag(s: Source): scala.collection.Map[Int, (Int, Int)] = + { + s.definitions.foreach(tagDefinition) + tags + } + def tagDefinitions(ds: Seq[Definition]) = ds.foreach(tagDefinition) + def tagDefinition(d: Definition) + { + d match + { + case c: ClassLike => tagClass(c) + case f: FieldLike => tagField(f) + case d: Def => tagDef(d) + case t: TypeDeclaration => tagTypeDeclaration(t) + case t: TypeAlias => tagTypeAlias(t) + } + } + def tagClass(c: ClassLike): Unit = + tagParameterizedDefinition(c) { + tagType(c.selfType) + tagStructure(c.structure) + } + def tagField(f: FieldLike) + { + tagType(f.tpe) + tagAnnotations(f.annotations) + } + def tagDef(d: Def): Unit = + tagParameterizedDefinition(d) { + tagValueParameters(d.valueParameters) + tagType(d.returnType) + } + def tagValueParameters(valueParameters: Seq[ParameterList]) = valueParameters.foreach(tagValueParameterList) + def tagValueParameterList(list: ParameterList) = list.parameters.foreach(tagValueParameter) + def tagValueParameter(parameter: MethodParameter) = tagType(parameter.tpe) + + def tagParameterizedDefinition[T <: ParameterizedDefinition](d: T)(tagExtra: => Unit) + { + tagAnnotations(d.annotations) + scope { + tagTypeParameters(d.typeParameters) + tagExtra + } + } + def tagTypeDeclaration(d: TypeDeclaration): Unit = + tagParameterizedDefinition(d) { + tagType(d.lowerBound) + tagType(d.upperBound) + } + def tagTypeAlias(d: TypeAlias): Unit = + tagParameterizedDefinition(d) { + tagType(d.tpe) + } + + def tagTypeParameters(parameters: Seq[TypeParameter]) = parameters.foreach(tagTypeParameter) + def tagTypeParameter(parameter: TypeParameter) + { + recordTypeParameter(parameter.id) + scope { + tagTypeParameters(parameter.typeParameters) + tagType(parameter.lowerBound) + tagType(parameter.upperBound) + } + } + def tagAnnotations(annotations: Seq[Annotation]) = tagTypes(annotations.map(_.base)) + + def tagTypes(ts: Seq[Type]) = ts.foreach(tagType) + def tagType(t: Type) + { + t match + { + case s: Structure => tagStructure(s) + case e: Existential => tagExistential(e) + case p: Polymorphic => tagPolymorphic(p) + case a: Annotated => tagAnnotated(a) + case p: Parameterized => tagParameterized(p) + case p: Projection => tagProjection(p) + case _: EmptyType | _: Singleton | _: ParameterRef => () + } + } + + def tagExistential(e: Existential) = tagParameters(e.clause, e.baseType) + def tagPolymorphic(p: Polymorphic) = tagParameters(p.parameters, p.baseType) + def tagProjection(p: Projection) = tagType(p.prefix) + def tagParameterized(p: Parameterized) + { + tagType(p.baseType) + tagTypes(p.typeArguments) + } + def tagAnnotated(a: Annotated) + { + tagType(a.baseType) + tagAnnotations(a.annotations) + } + def tagStructure(structure: Structure) + { + tagTypes(structure.parents) + tagDefinitions(structure.declared) + tagDefinitions(structure.inherited) + } + def tagParameters(parameters: Seq[TypeParameter], base: Type): Unit = + scope { + tagTypeParameters(parameters) + tagType(base) + } + + def scope(action: => Unit) + { + val saveIndex = index + index = 0 + level += 1 + + action + + level -= 1 + index = saveIndex + } + def recordTypeParameter(id: Int) + { + tags(id) = (level, index) + index += 1 + } +} \ No newline at end of file diff --git a/compile/interface/API.scala b/compile/interface/API.scala index 4f43897a2..b7778b88f 100644 --- a/compile/interface/API.scala +++ b/compile/interface/API.scala @@ -65,7 +65,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend if(pre == NoPrefix) { if(sym.isLocalClass) Constants.emptyType - else if(sym.isType) new xsbti.api.ParameterRef(sym.id) + else if(sym.isTypeParameterOrSkolem || sym.isExistential) new xsbti.api.ParameterRef(sym.id) else error("Unknown prefixless type: " + sym) } else if(sym.isRoot || sym.isRootPackage) Constants.emptyType @@ -121,6 +121,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend (tpe, Plain) new xsbti.api.MethodParameter(name, processType(t), hasDefault(s), special) } + build(s.info, Array(), Nil) } private def hasDefault(s: Symbol) = @@ -168,7 +169,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend 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)) + new xsbti.api.Structure(types(parents), processDefinitions(declared), Array())//processDefinitions(inherited)) private def processDefinitions(defs: List[Symbol]): Array[xsbti.api.Definition] = defs.toArray.map(definition) private def definition(sym: Symbol): xsbti.api.Definition = { @@ -226,11 +227,12 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend { val varianceInt = s.variance import xsbti.api.Variance._ + val annots = annotations(s) val variance = if(varianceInt < 0) Contravariant else if(varianceInt > 0) Covariant else Invariant s.info match { - case TypeBounds(low, high) => new xsbti.api.TypeParameter( s.id, typeParameters(s), variance, processType(low), processType(high) ) - case PolyType(typeParams, base) => new xsbti.api.TypeParameter( s.id, typeParameters(typeParams), variance, processType(base.bounds.lo), processType(base.bounds.hi)) + case TypeBounds(low, high) => new xsbti.api.TypeParameter( s.id, annots, typeParameters(s), variance, processType(low), processType(high) ) + case PolyType(typeParams, base) => new xsbti.api.TypeParameter( s.id, annots, typeParameters(typeParams), variance, processType(base.bounds.lo), processType(base.bounds.hi)) case x => error("Unknown type parameter info: " + x.getClass) } } diff --git a/interface/definition b/interface/definition index a89b238b9..9220a9a0e 100644 --- a/interface/definition +++ b/interface/definition @@ -1,10 +1,3 @@ -Source - packages : Package* - definitions: Definition* - -Package - name: String - Definition name: String access: Access @@ -29,91 +22,3 @@ Definition TypeDeclaration lowerBound: Type upperBound: Type - -Type - SimpleType - Projection - prefix : SimpleType - id : String - ParameterRef - id: Int - Singleton - path: Path - EmptyType - Parameterized - baseType : SimpleType - typeArguments: Type* - Annotated - baseType : SimpleType - annotations : Annotation* - Structure - parents : Type* - declarations: Definition* - inherited: Definition* - Existential - baseType : Type - clause: TypeParameter* - Polymorphic - baseType: Type - parameters: TypeParameter* - -Access - Public - Qualified - qualifier: Qualifier - Protected - Private - Pkg - -Qualifier - Unqualified - ThisQualifier - IdQualifier - value: String - -Modifiers - isAbstract: Boolean - isDeferred: Boolean - isOverride: Boolean - isFinal: Boolean - isSealed: Boolean - isImplicit: Boolean - isLazy: Boolean - isSynthetic: Boolean - -ParameterList - parameters: MethodParameter* - isImplicit: Boolean -MethodParameter - name: String - tpe: Type - hasDefault: Boolean - modifier: ParameterModifier - -TypeParameter - id: Int - typeParameters : TypeParameter* - variance: Variance - lowerBound: Type - upperBound: Type - -Annotation - base: SimpleType - arguments: AnnotationArgument* -AnnotationArgument - name: String - value: String - -enum Variance : Contravariant, Covariant, Invariant -enum ParameterModifier : Repeated, Plain, ByName -enum DefinitionType : Trait, ClassDef, Module, PackageModule - -Path - components: PathComponent* - -PathComponent - Super - qualifier: Path - This - Id - id: String \ No newline at end of file diff --git a/interface/other b/interface/other new file mode 100644 index 000000000..78fe98691 --- /dev/null +++ b/interface/other @@ -0,0 +1,68 @@ +Source + packages : Package* + definitions: Definition* + +Package + name: String + +Access + Public + Qualified + qualifier: Qualifier + Protected + Private + Pkg + +Qualifier + Unqualified + ThisQualifier + IdQualifier + value: String + +Modifiers + isAbstract: Boolean + isDeferred: Boolean + isOverride: Boolean + isFinal: Boolean + isSealed: Boolean + isImplicit: Boolean + isLazy: Boolean + isSynthetic: Boolean + +ParameterList + parameters: MethodParameter* + isImplicit: Boolean +MethodParameter + name: String + tpe: Type + hasDefault: Boolean + modifier: ParameterModifier + +TypeParameter + id: Int + annotations: Annotation* + typeParameters : TypeParameter* + variance: Variance + lowerBound: Type + upperBound: Type + +Annotation + base: SimpleType + arguments: AnnotationArgument* +AnnotationArgument + name: String + value: String + +enum Variance : Contravariant, Covariant, Invariant +enum ParameterModifier : Repeated, Plain, ByName +enum DefinitionType : Trait, ClassDef, Module, PackageModule + +Path + components: PathComponent* + +PathComponent + Super + qualifier: Path + This + Id + id: String \ No newline at end of file diff --git a/interface/type b/interface/type new file mode 100644 index 000000000..c516b62b9 --- /dev/null +++ b/interface/type @@ -0,0 +1,27 @@ + +Type + SimpleType + Projection + prefix : SimpleType + id : String + ParameterRef + id: Int + Singleton + path: Path + EmptyType + Parameterized + baseType : SimpleType + typeArguments: Type* + Annotated + baseType : SimpleType + annotations : Annotation* + Structure + parents : Type* + declared: Definition* + inherited: Definition* + Existential + baseType : Type + clause: TypeParameter* + Polymorphic + baseType: Type + parameters: TypeParameter* diff --git a/launch/src/main/resources/sbt/sbt.boot.properties b/launch/src/main/resources/sbt/sbt.boot.properties index 374f3d6b9..fb8bd0fb3 100644 --- a/launch/src/main/resources/sbt/sbt.boot.properties +++ b/launch/src/main/resources/sbt/sbt.boot.properties @@ -34,6 +34,6 @@ project.version: quick=set(1.0), new=prompt(Version)[1.0], fill=prompt(Version)[1.0] def.scala.version: quick=set(2.7.7), new=set(2.7.7), fill=set(2.7.7) build.scala.versions: quick=set(2.7.7), new=prompt(Scala version)[2.7.7], fill=prompt(Scala version)[2.7.7] - sbt.version: quick=set(0.6.9), new=prompt(sbt version)[0.6.9], fill=prompt(sbt version)[0.6.9] + sbt.version: quick=set(0.6.11), new=prompt(sbt version)[0.6.11], fill=prompt(sbt version)[0.6.11] project.scratch: quick=set(true) project.initialize: quick=set(true), new=set(true) \ No newline at end of file diff --git a/main/AggressiveCompiler.scala b/main/AggressiveCompiler.scala index bbeb50e16..762efbe59 100644 --- a/main/AggressiveCompiler.scala +++ b/main/AggressiveCompiler.scala @@ -28,8 +28,8 @@ class AggressiveCompiler extends xsbti.AppMain val classpath = outputDirectory map { _ ++ (cwd ** "*.jar") } val cacheDirectory = cwd / "target" / "cache" val options = Task(args.tail.toSeq) - val log = new ConsoleLogger with CompileLogger with IvyLogger { def verbose(msg: => String) = debug(msg) } - val componentManager = new ComponentManager(launcher.globalLock, app.components, log) + val log = new ConsoleLogger with CompileLogger with sbt.IvyLogger { def verbose(msg: => String) = debug(msg) } + val componentManager = new sbt.ComponentManager(launcher.globalLock, app.components, log) val compiler = Task(new AnalyzingCompiler(ScalaInstance(args.head, launcher), componentManager)) val compileTask = AggressiveCompile(sources, classpath, outputDirectory, options, cacheDirectory, compiler, log) diff --git a/main/alt.boot.properties b/main/alt.boot.properties index a24e8e815..f35ca3912 100644 --- a/main/alt.boot.properties +++ b/main/alt.boot.properties @@ -4,7 +4,7 @@ [app] org: org.scala-tools.sbt name: alternate-compiler-test - version: 0.6.10-SNAPSHOT + version: 0.6.12-SNAPSHOT class: xsbt.AggressiveCompiler components: xsbti cross-versioned: true diff --git a/notes b/notes index 71f0e44eb..d8945e05a 100644 --- a/notes +++ b/notes @@ -12,9 +12,9 @@ As usual: - Robust, flexible API ISSUES - - Scala issue #2265: cannot use structural types or libraries that use structural types, or OOME: PermGen will occur. Running/testing user code with structural types might also cause OOME, but is unlikely unless the Scala standard library or compiler uses structural types. - - API: changing package name in access qualifier does not work: must be API phase that doesn't correctly extract the ID - + - webapp: Jetty 7 + jsp + - java sources are not recompiled when jars change: possibly binary dependencies are not recorded? + TODO - launcher interface versioning - allow comments in datatype definition file @@ -22,8 +22,6 @@ TODO - have background triggered commands (~sync) update 0_6_Summary to mention different output directories. -look at permgen in Josh's ScalaTest -TrapExit handles System.exit(0) as nonzero exit code Task engine - method tasks will be normal tasks that pull the command line from a CommandLine task diff --git a/project/build/XSbt.scala b/project/build/XSbt.scala index 13b728e09..3c503e7a5 100644 --- a/project/build/XSbt.scala +++ b/project/build/XSbt.scala @@ -67,6 +67,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) //run in parallel override def parallelExecution = false def jlineRev = "0.9.94" + def jlineDep = "jline" % "jline" % jlineRev intransitive() override def managedStyle = ManagedStyle.Ivy val publishTo = Resolver.file("test-repo", new File("/var/dbwww/repo/")) @@ -74,7 +75,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) /* Subproject configurations*/ class LaunchProject(info: ProjectInfo) extends Base(info) with TestWithIO with TestDependencies with ProguardLaunch { - val jline = "jline" % "jline" % jlineRev intransitive() + val jline = jlineDep val ivy = "org.apache.ivy" % "ivy" % "2.0.0" def rawJarPath = jarPath override final def crossScalaVersions = Set.empty // don't need to cross-build, since the distributed jar is standalone (proguard) @@ -146,13 +147,21 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) def generatedBasePath = srcManagedPath / "main" / "java" /** Files that define the datatypes.*/ def apiDefinitionPaths: PathFinder = "definition" - def apiDefinitions = apiDefinitionPaths.get.toList.map(_.absolutePath) /** Delete up the generated sources*/ lazy val cleanManagedSrc = cleanTask(srcManagedPath) override def cleanAction = super.cleanAction dependsOn(cleanManagedSrc) /** Runs the generator compiled by 'compile', putting the classes in src_managed and processing the definitions 'apiDefinitions'. */ lazy val generateSource = generateSourceAction dependsOn(cleanManagedSrc, datatypeSub.compile) - def generateSourceAction = runTask(datatypeSub.getMainClass(true), datatypeSub.runClasspath, "xsbti.api" :: generatedBasePath.absolutePath :: apiDefinitions) + def generateSourceTask(immutable: Boolean, pkg: String, apiDefinitions: PathFinder): Task = + { + val m = if(immutable) "immutable" else "mutable" + generateSourceTask(m :: pkg :: generatedBasePath.absolutePath :: apiDefinitions.get.toList.map(_.absolutePath)) + } + def generateSourceTask(args: List[String]): Task = + runTask(datatypeSub.getMainClass(true), datatypeSub.runClasspath, args) + def generateSourceAction = + //generateSourceTask(false, "xsbti.api", "definition" +++ "type") && + generateSourceTask(true, "xsbti.api", "other" +++ "definition" +++ "type") /** compiles the generated sources */ override def compileAction = super.compileAction dependsOn(generateSource) } @@ -169,6 +178,8 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) def xTestClasspath = projectClasspath(Configurations.Test) def cID = "compiler-interface-src" override def componentID = Some(cID) + // necessary because jline is not distributed with 2.8 and we will get a compile error + //val jline = jlineDep artifacts(Artifact("jline", Map("e:component" -> cID))) override def ivyXML = diff --git a/tasks/standard/Compile.scala b/tasks/standard/Compile.scala index 406d4266e..bd5df77fd 100644 --- a/tasks/standard/Compile.scala +++ b/tasks/standard/Compile.scala @@ -66,16 +66,26 @@ class AggressiveCompile(val cacheDirectory: File, val compilerTask: Task[Analyzi val classpath = classpathChanges.checked val readTracker = tracker.read + // directories that are no longer on the classpath, not necessarily removed from the filesystem + val removedDirectories = classpathChanges.removed.filter(_.isDirectory) def uptodate(time: Long, files: Iterable[File]) = files.forall(_.lastModified <= time) - def isProductOutofdate(product: File) = !product.exists || !uptodate(product.lastModified, readTracker.sources(product)) - val outofdateProducts = readTracker.allProducts.filter(isProductOutofdate) + def isOutofdate(file: File, related: => Iterable[File]) = !file.exists || !uptodate(file.lastModified, related) + def isProductOutofdate(product: File) = isOutofdate(product, readTracker.sources(product)) + def inRemovedDirectory(file: File) = removedDirectories.exists(dir => FileUtilities.relativize(dir, file).isDefined) + def isUsedOutofdate(file: File) = classpathChanges.modified(file) || inRemovedDirectory(file) || isOutofdate(file, readTracker.usedBy(file)) - val rawInvalidatedSources = - classpathChanges.modified.flatMap(readTracker.usedBy) ++ - sourceChanges.removed.flatMap(readTracker.dependsOn) ++ - sourceChanges.modified ++ - outofdateProducts.flatMap(readTracker.sources) + // these are products that no longer exist or are older than the sources that produced them + val outofdateProducts = readTracker.allProducts.filter(isProductOutofdate) + // used classes and jars that a) no longer exist b) are no longer on the classpath or c) are newer than the sources that use them + val outofdateUses = readTracker.allUsed.filter(isUsedOutofdate) + + val modifiedSources = sourceChanges.modified + val invalidatedByClasspath = outofdateUses.flatMap(readTracker.usedBy) + val invalidatedByRemovedSrc = sourceChanges.removed.flatMap(readTracker.dependsOn) + val productsOutofdate = outofdateProducts.flatMap(readTracker.sources) + + val rawInvalidatedSources = modifiedSources ++ invalidatedByClasspath ++ invalidatedByRemovedSrc ++ productsOutofdate val invalidatedSources = scc(readTracker, rawInvalidatedSources) val sources = invalidatedSources.filter(_.exists) val previousAPIMap = Map() ++ sources.map { src => (src, APIFormat.read(readTracker.tag(src))) } diff --git a/util/datatype/GenerateDatatypes.scala b/util/datatype/GenerateDatatypes.scala index 7da31f03f..56ca959ce 100644 --- a/util/datatype/GenerateDatatypes.scala +++ b/util/datatype/GenerateDatatypes.scala @@ -5,29 +5,31 @@ import java.io.File /** Generates a datatype hierarchy from a definition file.*/ object GenerateDatatypes { - /** Arguments: +*/ + /** Arguments: ('mutable' | 'immutable') +*/ def main(args: Array[String]) { - if(args.length < 3) + if(args.length < 4) { - System.err.println("Invalid number of arguments, expected package, base directory, and files to process") + System.err.println("Invalid number of arguments, expected 'mutable' or 'immutable', package, base directory, and files to process") System.exit(1) } else { - val packageName = args(0).trim + val immutable = args(0).trim.toLowerCase == "immutable" + + val packageName = args(1).trim require(!packageName.isEmpty) - val baseDirectory = new File(args(1)) + val baseDirectory = new File(args(2)) baseDirectory.mkdirs - val files = args.drop(2).map(new File(_)) + val files = args.drop(3).map(new File(_)) // parse the files, getting all interface and enums val parser = new DatatypeParser val definitions = files.flatMap(parser.parseFile) // create the interfaces, enums, and class implementations - val generator = new Generator(packageName, baseDirectory) + val generator = if(immutable) new ImmutableGenerator(packageName, baseDirectory) else new MutableGenerator(packageName, baseDirectory) generator.writeDefinitions(definitions) } } diff --git a/util/datatype/Generator.scala b/util/datatype/Generator.scala index bae5a3b0f..8f7ff1f58 100644 --- a/util/datatype/Generator.scala +++ b/util/datatype/Generator.scala @@ -3,6 +3,32 @@ package xsbt.api import java.io.File import xsbt.FileUtilities +import Generator._ + +abstract class GeneratorBase(val basePkgName: String, val baseDirectory: File) extends NotNull +{ + def writeDefinitions(ds: Iterable[Definition]) = Generator.writeDefinitions(ds)(writeDefinition) + def writeDefinition(d: Definition) = d match { case e: EnumDef => writeEnum(e); case c: ClassDef => writeClass(c) } + def writeEnum(e: EnumDef) + { + val content = + "public enum " + e.name + " {" + + e.members.mkString("\n\t", ",\n\t", "\n") + + "}" + writeSource(e.name, basePkgName, content) + } + def writeClass(c: ClassDef): Unit + + def writeSource(name: String, pkgName: String, content: String) + { + import Paths._ + val file =baseDirectory / packagePath(pkgName) / (name+ ".java") + file.getParentFile.mkdirs() + FileUtilities.write(file, "package " + pkgName + ";\n\n" + content) + } + private def packagePath(pkgName: String) = pkgName.replace('.', File.separatorChar) +} + /** 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 @@ -15,30 +41,9 @@ import xsbt.FileUtilities * *.@param baseDirectory output directory for sources * @param pkgName package that classes will be defined in*/ -class Generator(pkgName: String, baseDirectory: File) +class ImmutableGenerator(pkgName: String, baseDir: File) extends GeneratorBase(pkgName, baseDir) { - def writeDefinitions(ds: Iterable[Definition]) = - { - val (_, duplicates) = - ( (Set[String](), Set[String]()) /: ds.map(_.name)) { - case ((nameSet, duplicates), name) => - if(nameSet.contains(name)) (nameSet, duplicates + name) else (nameSet + name, duplicates) - } - if(duplicates.isEmpty) - ds.foreach(writeDefinition) - else - error("Duplicate names:\n\t" + duplicates.mkString("\n\t")) - } - def writeDefinition(d: Definition) = d match { case e: EnumDef => write(e); case c: ClassDef => write(c) } - def write(e: EnumDef) - { - val content = - "public enum " + e.name + " {" + - e.members.mkString("\n\t", ",\n\t", "\n") + - "}" - writeSource(e.name, content) - } - def write(c: ClassDef): Unit = writeSource(c.name, classContent(c)) + def writeClass(c: ClassDef): Unit = writeSource(c.name, basePkgName, classContent(c)) def classContent(c: ClassDef): String = { val hasParent = c.parent.isDefined @@ -53,8 +58,6 @@ class Generator(pkgName: String, baseDirectory: File) val inherited = c.inheritedMembers 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 = method("public", "String", "toString", "", "\"" + c.name + "(\" + " + parametersString + "+ \")\"") val constructor = "public " + c.name + "(" + parameters.mkString(", ") + ")\n\t" + "{\n\t\t" + @@ -67,23 +70,82 @@ class Generator(pkgName: String, baseDirectory: File) "{\n\t" + constructor + "\n\t" + (fields ++ accessors).mkString("\n\t") + "\n\t" + - toStringMethod + "\n\t" + - "}" + toStringMethod(c) + "\n" + + "}\n" } + +} +class MutableGenerator(pkgName: String, baseDir: File) extends GeneratorBase(pkgName, baseDir) +{ + def writeClass(c: ClassDef): Unit = + { + writeSource(c.name, basePkgName, interfaceContent(c)) + writeSource(implName(c.name), basePkgName + ".mutable", implContent(c)) + } + def interfaceContent(c: ClassDef): String = + { + val normalizedMembers = c.members.map(normalize) + val getters = normalizedMembers.map(m => "public " + m.asJavaDeclaration + "();") + val setters = normalizedMembers.map(m => "public void " + m.name + "(" + m.javaType + " newValue);") + val extendsPhrase = c.parent.map(_.name).map(" extends " + _).getOrElse("") + + ("public interface " + c.name + extendsPhrase + "\n" + + "{\n\t" + + (setters ++ getters).mkString("\n\t") + "\n" + + "}\n") + } + def implContent(c: ClassDef): String = + { + val normalizedMembers = c.members.map(normalize) + val fields = normalizedMembers.map(m => "private " + m.asJavaDeclaration + ";") + val getters = normalizedMembers.map(m => "public final " + m.asJavaDeclaration + "()\n\t{\n\t\treturn " + m.name + ";\n\t}") + val setters = normalizedMembers.map(m => "public final void " + m.name + "(" + m.javaType + " newValue)\n\t{\n\t\t" + m.name + " = newValue;\n\t}") + val extendsClass = c.parent.map(p => implName(p.name)) + val serializable = if(c.parent.isDefined) Nil else "java.io.Serializable" :: Nil + val implements = c.name :: serializable + val extendsPhrase = extendsClass.map(" extends " + _).getOrElse("") + " implements " + implements.mkString(", ") + + ("import java.util.Arrays;\n" + + "import java.util.List;\n" + + "import " + pkgName + ".*;\n\n" + + "public class " + implName(c.name) + extendsPhrase + "\n" + + "{\n\t" + + (fields ++ getters ++ setters).mkString("\n\t") + "\n\t" + + toStringMethod(c) + "\n" + + "}\n") + } + +} +object Generator +{ + def methodSignature(modifiers: String, returnType: String, name: String, parameters: String) = + modifiers + " " + returnType + " " + name + "(" + parameters + ")" def method(modifiers: String, returnType: String, name: String, parameters: String, content: String) = - modifiers + " " + returnType + " " + name + "(" + parameters + ")\n\t{\n\t\treturn " + content + ";\n\t}" + methodSignature(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 = m.mapType(tpe => if(primitives(tpe.toLowerCase)) tpe.toLowerCase else tpe) - - def writeSource(name: String, content: String) - { - import Paths._ - val file =baseDirectory / packagePath / (name+ ".java") - file.getParentFile.mkdirs() - FileUtilities.write(file, "package " + pkgName + ";\n\n" + content) - } - private def packagePath = pkgName.replace('.', File.separatorChar) private val primitives = Set("int", "boolean", "float", "long", "short", "byte", "char", "double") -} + + def toStringMethod(c: ClassDef): String = + { + val allMembers = c.allMembers.map(normalize) + val parametersString = if(allMembers.isEmpty) "\"\"" else allMembers.map(m => fieldToString(m.name, m.single)).mkString(" + \", \" + ") + method("public", "String", "toString", "", "\"" + c.name + "(\" + " + parametersString + "+ \")\"") + } + + def writeDefinitions(ds: Iterable[Definition])(writeDefinition: Definition => Unit) + { + val (_, duplicates) = + ( (Set[String](), Set[String]()) /: ds.map(_.name)) { + case ((nameSet, duplicates), name) => + if(nameSet.contains(name)) (nameSet, duplicates + name) else (nameSet + name, duplicates) + } + if(duplicates.isEmpty) + ds.foreach(writeDefinition) + else + error("Duplicate names:\n\t" + duplicates.mkString("\n\t")) + } + def implName(name: String) = name + "0" +} \ No newline at end of file