2011-01-19 00:24:11 +01:00
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
2010-09-08 20:29:00 +02:00
package sbt
2010-12-29 22:07:17 +01:00
import Types._
2010-12-13 03:33:32 +01:00
sealed trait Settings [ Scope ]
{
2011-01-19 00:24:11 +01:00
def data : Map [ Scope , AttributeMap ]
def keys ( scope : Scope ) : Set [ AttributeKey [ _ ] ]
def scopes : Set [ Scope ]
2010-12-13 03:33:32 +01:00
def get [ T ] ( scope : Scope , key : AttributeKey [ T ] ) : Option [ T ]
def set [ T ] ( scope : Scope , key : AttributeKey [ T ] , value : T ) : Settings [ Scope ]
}
2010-12-29 22:07:17 +01:00
private final class Settings0 [ Scope ] ( val data : Map [ Scope , AttributeMap ] , val delegates : Scope => Seq [ Scope ] ) extends Settings [ Scope ]
2010-09-08 20:29:00 +02:00
{
2011-01-19 00:24:11 +01:00
def scopes : Set [ Scope ] = data . keySet . toSet
def keys ( scope : Scope ) = data ( scope ) . keys . toSet
2010-12-29 22:07:17 +01:00
2010-12-13 03:33:32 +01:00
def get [ T ] ( scope : Scope , key : AttributeKey [ T ] ) : Option [ T ] =
2010-12-29 22:07:17 +01:00
delegates ( scope ) . toStream . flatMap ( sc => scopeLocal ( sc , key ) ) . headOption
2010-12-13 03:33:32 +01:00
private def scopeLocal [ T ] ( scope : Scope , key : AttributeKey [ T ] ) : Option [ T ] =
( data get scope ) . flatMap ( _ get key )
def set [ T ] ( scope : Scope , key : AttributeKey [ T ] , value : T ) : Settings [ Scope ] =
{
val map = ( data get scope ) getOrElse AttributeMap . empty
val newData = data . updated ( scope , map . put ( key , value ) )
2010-12-29 22:07:17 +01:00
new Settings0 ( newData , delegates )
2010-12-13 03:33:32 +01:00
}
2010-09-08 20:29:00 +02:00
}
2010-12-29 22:07:17 +01:00
// delegates should contain the input Scope as the first entry
2011-01-19 00:24:11 +01:00
// this trait is intended to be mixed into an object
trait Init [ Scope ]
2010-09-08 20:29:00 +02:00
{
2010-12-29 22:07:17 +01:00
final case class ScopedKey [ T ] ( scope : Scope , key : AttributeKey [ T ] )
2010-09-08 20:29:00 +02:00
2010-12-29 22:07:17 +01:00
type SettingSeq [ T ] = Seq [ Setting [ T ] ]
type ScopedMap = IMap [ ScopedKey , SettingSeq ]
type CompiledMap = Map [ ScopedKey [ _ ] , Compiled ]
type MapScoped = ScopedKey ~> ScopedKey
2010-12-13 03:33:32 +01:00
2010-12-29 22:07:17 +01:00
def value [ T ] ( key : ScopedKey [ T ] ) ( value : => T ) : Setting [ T ] = new Value ( key , value _ )
def update [ T ] ( key : ScopedKey [ T ] ) ( f : T => T ) : Setting [ T ] = app ( key , key : ^: KNil ) ( h => f ( h . head ) )
def app [ HL <: HList , T ] ( key : ScopedKey [ T ] , inputs : KList [ ScopedKey , HL ] ) ( f : HL => T ) : Setting [ T ] = new Apply ( key , f , inputs )
2011-01-19 00:24:11 +01:00
def uniform [ S ,T ] ( key : ScopedKey [ T ] , inputs : Seq [ ScopedKey [ S ] ] ) ( f : Seq [ S ] => T ) : Setting [ T ] = new Uniform ( key , f , inputs )
def kapp [ HL <: HList , M [ _ ] , T ] ( key : ScopedKey [ T ] , inputs : KList [ ( { type l [ t ] = ScopedKey [ M [ t ] ] } ) # l , HL ] ) ( f : KList [ M , HL ] => T ) : Setting [ T ] = new KApply [ HL , M , T ] ( key , f , inputs )
2010-12-13 03:33:32 +01:00
2011-01-19 00:24:11 +01:00
// the following is a temporary workaround for the "... cannot be instantiated from ..." bug, which renders 'kapp' above unusable outside this source file
class KApp [ HL <: HList , M [ _ ] , T ] {
type Composed [ S ] = ScopedKey [ M [ S ] ]
def apply ( key : ScopedKey [ T ] , inputs : KList [ Composed , HL ] ) ( f : KList [ M , HL ] => T ) : Setting [ T ] = new KApply [ HL , M , T ] ( key , f , inputs )
}
def empty ( implicit delegates : Scope => Seq [ Scope ] ) : Settings [ Scope ] = new Settings0 ( Map . empty , delegates )
2010-12-29 22:07:17 +01:00
def asTransform ( s : Settings [ Scope ] ) : ScopedKey ~> Id = new ( ScopedKey ~> Id ) {
2011-01-19 00:24:11 +01:00
def apply [ T ] ( k : ScopedKey [ T ] ) : T = getValue ( s , k )
2010-12-13 03:33:32 +01:00
}
2011-01-19 00:24:11 +01:00
def getValue [ T ] ( s : Settings [ Scope ] , k : ScopedKey [ T ] ) = s . get ( k . scope , k . key ) . get
def asFunction [ T ] ( s : Settings [ Scope ] ) : ScopedKey [ T ] => T = k => getValue ( s , k )
2010-12-13 03:33:32 +01:00
2011-01-19 00:24:11 +01:00
def make ( init : Seq [ Setting [ _ ] ] ) ( implicit delegates : Scope => Seq [ Scope ] ) : Settings [ Scope ] =
2010-12-13 03:33:32 +01:00
{
2010-12-29 22:07:17 +01:00
// group by Scope/Key, dropping dead initializations
val sMap : ScopedMap = grouped ( init )
// delegate references to undefined values according to 'delegates'
2011-01-19 00:24:11 +01:00
val dMap : ScopedMap = delegate ( sMap ) ( delegates )
2010-12-29 22:07:17 +01:00
// merge Seq[Setting[_]] into Compiled
val cMap : CompiledMap = compile ( dMap )
// order the initializations. cyclic references are detected here.
val ordered : Seq [ Compiled ] = sort ( cMap )
// evaluation: apply the initializations.
applyInits ( ordered )
2010-12-13 03:33:32 +01:00
}
2010-12-29 22:07:17 +01:00
def sort ( cMap : CompiledMap ) : Seq [ Compiled ] =
Dag . topologicalSort ( cMap . values ) ( _ . dependencies . map ( cMap ) )
def compile ( sMap : ScopedMap ) : CompiledMap =
sMap . toSeq . map { case ( k , ss ) =>
val deps = ss flatMap { _ . dependsOn }
val eval = ( settings : Settings [ Scope ] ) => ( settings /: ss ) ( applySetting )
( k , new Compiled ( deps , eval ) )
2010-12-13 03:33:32 +01:00
} toMap ;
2010-12-29 22:07:17 +01:00
def grouped ( init : Seq [ Setting [ _ ] ] ) : ScopedMap =
( ( IMap . empty : ScopedMap ) /: init ) ( ( m , s ) => add ( m , s ) )
def add [ T ] ( m : ScopedMap , s : Setting [ T ] ) : ScopedMap =
m . mapValue [ T ] ( s . key , Nil , ss => append ( ss , s ) )
def append [ T ] ( ss : Seq [ Setting [ T ] ] , s : Setting [ T ] ) : Seq [ Setting [ T ] ] =
if ( s . definitive ) s : : Nil else ss :+ s
2011-01-19 00:24:11 +01:00
def delegate ( sMap : ScopedMap ) ( implicit delegates : Scope => Seq [ Scope ] ) : ScopedMap =
2010-12-13 03:33:32 +01:00
{
2011-01-26 04:14:02 +01:00
def refMap ( refKey : ScopedKey [ _ ] ) = new ( ScopedKey ~> ScopedKey ) { def apply [ T ] ( k : ScopedKey [ T ] ) =
delegateForKey ( sMap , k , delegates ( k . scope ) , refKey )
}
val f = new ( SettingSeq ~> SettingSeq ) { def apply [ T ] ( ks : Seq [ Setting [ T ] ] ) =
ks . map { s => s mapReferenced refMap ( s . key ) }
}
2010-12-29 22:07:17 +01:00
sMap mapValues f
2010-12-13 03:33:32 +01:00
}
2011-01-24 04:34:17 +01:00
private [ this ] def delegateForKey [ T ] ( sMap : ScopedMap , k : ScopedKey [ T ] , scopes : Seq [ Scope ] , refKey : ScopedKey [ _ ] ) : ScopedKey [ T ] =
2010-12-29 22:07:17 +01:00
{
val scache = PMap . empty [ ScopedKey , ScopedKey ]
def resolve ( search : Seq [ Scope ] ) : ScopedKey [ T ] =
search match {
case Seq ( ) => throw new Uninitialized ( k )
case Seq ( x , xs @ _ * ) =>
val sk = ScopedKey ( x , k . key )
scache . getOrUpdate ( sk , if ( defines ( sMap , sk , refKey ) ) sk else resolve ( xs ) )
}
resolve ( scopes )
2010-12-13 03:33:32 +01:00
}
2010-12-29 22:07:17 +01:00
private [ this ] def defines ( map : ScopedMap , key : ScopedKey [ _ ] , refKey : ScopedKey [ _ ] ) : Boolean =
( map get key ) match { case Some ( Seq ( x , _ * ) ) => ( refKey != key ) || x . definitive ; case _ => false }
2011-01-19 00:24:11 +01:00
private [ this ] def applyInits ( ordered : Seq [ Compiled ] ) ( implicit delegates : Scope => Seq [ Scope ] ) : Settings [ Scope ] =
2010-12-29 22:07:17 +01:00
( empty /: ordered ) { ( m , comp ) => comp . eval ( m ) }
2010-12-13 03:33:32 +01:00
2011-01-19 00:24:11 +01:00
private [ this ] def applySetting [ T ] ( map : Settings [ Scope ] , setting : Setting [ T ] ) : Settings [ Scope ] =
{
def execK [ HL <: HList , M [ _ ] ] ( a : KApply [ HL , M , T ] ) =
map . set ( a . key . scope , a . key . key , a . f ( a . inputs . transform [ M ] ( nestCon [ ScopedKey , Id , M ] ( asTransform ( map ) ) ) ) )
setting match
2010-09-08 20:29:00 +02:00
{
2010-12-29 22:07:17 +01:00
case s : Value [ T ] => map . set ( s . key . scope , s . key . key , s . value ( ) )
2011-01-19 00:24:11 +01:00
case u : Uniform [ s , T ] => map . set ( u . key . scope , u . key . key , u . f ( u . inputs map asFunction ( map ) ) )
case a : Apply [ hl , T ] => map . set ( a . key . scope , a . key . key , a . f ( a . inputs down asTransform ( map ) ) )
case ka : KApply [ hl , m , T ] => execK [ hl , m ] ( ka ) // separate method needed to workaround bug where m is not recognized as higher-kinded in inline version
2010-09-08 20:29:00 +02:00
}
2011-01-19 00:24:11 +01:00
}
2010-12-13 03:33:32 +01:00
2010-12-29 22:07:17 +01:00
final class Uninitialized ( key : ScopedKey [ _ ] ) extends Exception ( "Update on uninitialized setting " + key . key . label + " (in " + key . scope + ")" )
final class Compiled ( val dependencies : Iterable [ ScopedKey [ _ ] ] , val eval : Settings [ Scope ] => Settings [ Scope ] )
2010-12-13 03:33:32 +01:00
sealed trait Setting [ T ]
{
2010-12-29 22:07:17 +01:00
def key : ScopedKey [ T ]
def definitive : Boolean
def dependsOn : Seq [ ScopedKey [ _ ] ]
2011-01-19 00:24:11 +01:00
def mapReferenced ( g : MapScoped ) : Setting [ T ]
def mapKey ( g : MapScoped ) : Setting [ T ]
2010-12-13 03:33:32 +01:00
}
2010-12-29 22:07:17 +01:00
private [ this ] final class Value [ T ] ( val key : ScopedKey [ T ] , val value : ( ) => T ) extends Setting [ T ]
2010-12-13 03:33:32 +01:00
{
2010-12-29 22:07:17 +01:00
def definitive = true
def dependsOn = Nil
2011-01-19 00:24:11 +01:00
def mapReferenced ( g : MapScoped ) = this
def mapKey ( g : MapScoped ) : Setting [ T ] = new Value ( g ( key ) , value )
2010-09-08 20:29:00 +02:00
}
2010-12-29 22:07:17 +01:00
private [ this ] final class Apply [ HL <: HList , T ] ( val key : ScopedKey [ T ] , val f : HL => T , val inputs : KList [ ScopedKey , HL ] ) extends Setting [ T ]
2010-12-13 03:33:32 +01:00
{
2010-12-29 22:07:17 +01:00
def definitive = ! inputs . toList . contains ( key )
2011-01-19 00:24:11 +01:00
def dependsOn = remove ( inputs . toList , key )
2010-12-29 22:07:17 +01:00
def mapReferenced ( g : MapScoped ) = new Apply ( key , f , inputs transform g )
2011-01-19 00:24:11 +01:00
def mapKey ( g : MapScoped ) : Setting [ T ] = new Apply ( g ( key ) , f , inputs )
}
private [ this ] final class KApply [ HL <: HList , M [ _ ] , T ] ( val key : ScopedKey [ T ] , val f : KList [ M , HL ] => T , val inputs : KList [ ( { type l [ t ] = ScopedKey [ M [ t ] ] } ) # l , HL ] ) extends Setting [ T ]
{
def definitive = ! inputs . toList . contains ( key )
def dependsOn = remove ( unnest ( inputs . toList ) , key )
def mapReferenced ( g : MapScoped ) = new KApply [ HL , M , T ] ( key , f , inputs . transform [ ( { type l [ t ] = ScopedKey [ M [ t ] ] } ) # l ] ( nestCon ( g ) ) )
def mapKey ( g : MapScoped ) : Setting [ T ] = new KApply [ HL , M , T ] ( g ( key ) , f , inputs )
private [ this ] def unnest ( l : List [ ScopedKey [ M [ T ] ] forSome { type T } ] ) : List [ ScopedKey [ _ ] ] = l . asInstanceOf [ List [ ScopedKey [ _ ] ] ]
}
private [ this ] final class Uniform [ S , T ] ( val key : ScopedKey [ T ] , val f : Seq [ S ] => T , val inputs : Seq [ ScopedKey [ S ] ] ) extends Setting [ T ]
{
def definitive = ! inputs . contains ( key )
def dependsOn = remove ( inputs , key )
def mapReferenced ( g : MapScoped ) = new Uniform ( key , f , inputs map g . fn [ S ] )
def mapKey ( g : MapScoped ) : Setting [ T ] = new Uniform ( g ( key ) , f , inputs )
2010-12-13 03:33:32 +01:00
}
2011-01-19 00:24:11 +01:00
private def remove [ T ] ( s : Seq [ T ] , v : T ) = s filterNot ( _ == v )
2010-12-13 03:33:32 +01:00
}