Permalink
Browse files

Refactor Env; add "import" tag to basic Env

  • Loading branch information...
1 parent 72bc16c commit 69cebbf31a37ac6d8b6220d1ff33c4b66a3e15f0 @davegurnell committed Jun 6, 2012
View
@@ -2,7 +2,7 @@ import sbt._
import sbt.Keys._
object Build extends Build {
- val tipiVersion = "0.1-M3"
+ val tipiVersion = "0.1-M4"
lazy val scalatest = "org.scalatest" %% "scalatest" % "1.7.1"
@@ -57,6 +57,16 @@ case class Arguments(arguments: List[Argument]) {
}
def toList = arguments
+
+ def toEnv(base: Env): Env = {
+ arguments.foldLeft(base) {
+ (accum, arg) =>
+ arg.transform(accum) match {
+ case Some(tx) => accum + (arg.name -> tx)
+ case None => accum
+ }
+ }
+ }
}
object Arguments {
@@ -1,155 +1,138 @@
package tipi.core
trait Env {
+ import Env._
+
def get(id: Id): Option[Transform]
def ids: Seq[Id]
- def + (binding: (Id, Transform)): Env = CompoundEnv(SingleEnv(binding), this)
- def ++ (that: Env): Env = CompoundEnv(that, this)
- def prefix(prefix: Id): Env = PrefixEnv(prefix, this)
- def only(ids: Id *) = OnlyEnv(ids.toList, this)
- def except(ids: Id *) = ExceptEnv(ids.toList, this)
+ def + (binding: (Id, Transform)): Env = Union(Env(binding), this)
+ def ++ (that: Env): Env = Union(that, this)
+ def prefix(prefix: Id): Env = Prefix(prefix, this)
+ def only(ids: Id *) = Only(ids.toList, this)
+ def except(ids: Id *) = Except(ids.toList, this)
}
-case class CompoundEnv(a: Env, b: Env) extends Env {
- def get(id: Id): Option[Transform] = {
- a.get(id) orElse b.get(id)
+object Env {
+ def apply(bindings: (Id, Transform) *): Env = {
+ Env.Simple(Map(bindings : _*))
}
- def ids: Seq[Id] = {
- a.ids ++ b.ids
+ def loadClass(name: String): Env = {
+ Class.forName(name).newInstance.asInstanceOf[Env]
}
-}
-case class SingleEnv(binding: (Id, Transform)) extends Env {
- val id = binding._1
- val transform = binding._2
+ case object Empty extends Env {
+ def get(id: Id): Option[Transform] = None
- def get(id: Id): Option[Transform] = {
- if(id == this.id) Some(transform) else None
+ def ids: Seq[Id] = Seq.empty[Id]
}
- def ids: Seq[Id] = {
- List(id)
- }
-}
+ case class Simple(bindings: Map[Id, Transform]) extends Env {
+ def get(id: Id): Option[Transform] = {
+ bindings.get(id)
+ }
-case class PrefixEnv(prefix: Id, inner: Env) extends Env {
- def get(id: Id): Option[Transform] = {
- if(id.name startsWith prefix.name) {
- inner.get(Id(id.name substring prefix.name.length))
- } else None
+ def ids: Seq[Id] = {
+ bindings.keys.toList
+ }
}
- def ids: Seq[Id] = {
- inner.ids.map(_ prefix prefix)
- }
-}
+ case class Union(a: Env, b: Env) extends Env {
+ def get(id: Id): Option[Transform] = {
+ a.get(id) orElse b.get(id)
+ }
-case class OnlyEnv(allowed: List[Id], inner: Env) extends Env {
- def get(id: Id): Option[Transform] = {
- if(allowed contains id) inner.get(id) else None
+ def ids: Seq[Id] = {
+ a.ids ++ b.ids
+ }
}
- def ids: Seq[Id] = {
- inner.ids filter (allowed contains _)
- }
-}
+ case class Prefix(prefix: Id, inner: Env) extends Env {
+ def get(id: Id): Option[Transform] = {
+ if(id.name startsWith prefix.name) {
+ inner.get(Id(id.name substring prefix.name.length))
+ } else None
+ }
-case class ExceptEnv(allowed: List[Id], inner: Env) extends Env {
- def get(id: Id): Option[Transform] = {
- if(allowed contains id) None else inner.get(id)
+ def ids: Seq[Id] = {
+ inner.ids.map(_ prefix prefix)
+ }
}
- def ids: Seq[Id] = {
- inner.ids filterNot (allowed contains _)
- }
-}
+ case class Only(allowed: List[Id], inner: Env) extends Env {
+ def get(id: Id): Option[Transform] = {
+ if(allowed contains id) inner.get(id) else None
+ }
-case class MapEnv(val bindings: Map[Id, Transform]) extends Env {
- def this(bindings: (Id, Transform) *) = {
- this(Map(bindings : _*))
+ def ids: Seq[Id] = {
+ inner.ids filter (allowed contains _)
+ }
}
- def get(id: Id): Option[Transform] = {
- bindings.get(id)
- }
+ case class Except(allowed: List[Id], inner: Env) extends Env {
+ def get(id: Id): Option[Transform] = {
+ if(allowed contains id) None else inner.get(id)
+ }
- def ids: Seq[Id] = {
- bindings.keys.toList
+ def ids: Seq[Id] = {
+ inner.ids filterNot (allowed contains _)
+ }
}
-}
-trait CustomEnv extends Env {
- lazy val bindings = Map {
- this.getClass.getMethods.toList.filter(methodTypesOk _).map { method =>
- Id(method.getName) -> methodToTransform(method)
- } : _*
- }
+ trait Custom extends Env {
+ lazy val bindings = Map {
+ this.getClass.getMethods.toList.filter(methodTypesOk _).map { method =>
+ Id(method.getName) -> methodToTransform(method)
+ } : _*
+ }
- private def methodTypesOk(method: java.lang.reflect.Method): Boolean = {
- method.getParameterTypes.toList == CustomEnv.transformArgTypes &&
- method.getReturnType == CustomEnv.transformReturnType
- }
+ private def methodTypesOk(method: java.lang.reflect.Method): Boolean = {
+ method.getParameterTypes.toList == Env.Custom.transformArgTypes &&
+ method.getReturnType == Env.Custom.transformReturnType
+ }
- private def methodToTransform(method: java.lang.reflect.Method): Transform = {
- Transform.Full((in: (Env, Doc)) => method.invoke(this, in._1, in._2).asInstanceOf[(Env, Doc)])
- }
+ private def methodToTransform(method: java.lang.reflect.Method): Transform = {
+ Transform.Full((in: (Env, Doc)) => method.invoke(this, in._1, in._2).asInstanceOf[(Env, Doc)])
+ }
- def get(id: Id): Option[Transform] = {
- bindings.get(id)
- }
+ def get(id: Id): Option[Transform] = {
+ bindings.get(id)
+ }
- def ids: Seq[Id] = {
- bindings.keySet.toList
+ def ids: Seq[Id] = {
+ bindings.keySet.toList
+ }
}
-}
-object CustomEnv {
- val transformArgTypes = List(classOf[Env], classOf[Doc])
- val transformReturnType = classOf[Tuple2[Env, Doc]]
-}
-
-object Env {
- def apply(bindings: (Id, Transform) *): Env = {
- MapEnv(Map(bindings : _*))
+ object Custom {
+ val transformArgTypes = List(classOf[Env], classOf[Doc])
+ val transformReturnType = classOf[Tuple2[Env, Doc]]
}
- val empty = Env()
+ object Basic extends Env.Custom {
+ def `def`(envIn: Env, docIn: Doc): (Env, Doc) = {
+ docIn match {
+ case Block(_, args, Range.Empty) =>
+ (args.toEnv(envIn), Range.Empty)
- val basic = empty ++ Env(
- Id("def") -> new Transform {
- def isDefinedAt(in: (Env, Doc)) = {
- val (env, doc) = in
- doc match {
- case Block(Id("def"), _, _) => true
- case _ => false
- }
- }
+ case block @ Block(_, Arguments(UnitArgument(name) :: _), _) =>
+ (envIn + (name -> Template(envIn, block)), Range.Empty)
- def apply(in: (Env, Doc)): (Env, Doc) = {
- val (env, doc) = in
- doc match {
- case Block(_, args, Range.Empty) =>
- (Env.fromArgs(env, args), Range.Empty)
-
- case block @ Block(_, Arguments(UnitArgument(name) :: _), _) =>
- (env + (name -> Template(block, env)), Range.Empty)
-
- case _ => sys.error("Invalid 'def' block")
- }
+ case _ =>
+ sys.error("Invalid 'def' block")
}
-
- override def toString = "define"
}
- )
- def fromArgs(initial: Env, args: Arguments): Env = {
- args.toList.foldLeft(initial) {
- (accum, arg) =>
- arg.transform(accum) match {
- case Some(tx) => accum + (arg.name -> tx)
- case None => accum
+ def `import`(envIn: Env, docIn: Doc): (Env, Doc) = docIn match {
+ case Block(_, args, _) =>
+ args.string(envIn, Id("class")) match {
+ case Some(name) =>
+ val prefix = args.string(envIn, Id("prefix")).getOrElse("")
+ (envIn ++ Env.loadClass(name).prefix(Id(prefix)), Range.Empty)
+
+ case _ =>
+ sys.error("Bad import tag: no 'source' or 'class' parameter")
}
}
}
@@ -1,11 +1,11 @@
package tipi.core
-case class Template(val defn: Block, val globalEnv: Env) extends Transform with TransformImplicits {
+case class Template(val globalEnv: Env, val defn: Block) extends Transform with TransformImplicits {
import Template._
lazy val defnName: Id = defn.args.toList.head.name
lazy val defnArgNames = defn.args.toList.tail.map(_.name)
- lazy val defnEnv: Env = Env.fromArgs(globalEnv, Arguments(defn.args.toList.tail))
+ lazy val defnEnv: Env = Arguments(defn.args.toList.tail).toEnv(globalEnv)
// println(
// """
@@ -17,15 +17,15 @@ case class Template(val defn: Block, val globalEnv: Env) extends Transform with
// )
def localEnv(callingEnv: Env, doc: Block): Env = {
- val thisKwEnv = Env.empty + (Id("this") -> Expand((callingEnv, doc.body))._2)
+ val thisKwEnv = Env(Id("this") -> Expand((callingEnv, doc.body))._2)
- val argsEnv = Env.fromArgs(callingEnv, doc.args).only(defnArgNames : _*)
+ val argsEnv = doc.args.toEnv(callingEnv).only(defnArgNames : _*)
val bindEnv = {
def loop(env: Env, doc: Doc): Env = {
doc match {
case Block(Id("bind"), args, Range.Empty) =>
- env ++ Env.fromArgs(callingEnv, args).only(defnArgNames : _*)
+ env ++ args.toEnv(callingEnv).only(defnArgNames : _*)
case Block(Id("bind"), Arguments(UnitArgument(name) :: _), body) =>
env + (name -> Expand((callingEnv, body))._2)
@@ -37,11 +37,11 @@ case class Template(val defn: Block, val globalEnv: Env) extends Transform with
}
}
- loop(Env.empty, doc.body).only(defnArgNames : _*)
+ loop(Env.Empty, doc.body).only(defnArgNames : _*)
}
val bindKwEnv =
- Env.empty + (Id("bind") -> Transform.Identity)
+ Env.Empty + (Id("bind") -> Transform.Identity)
defnEnv ++ argsEnv ++ bindEnv ++ thisKwEnv ++ bindKwEnv
}
@@ -8,7 +8,7 @@ case class Tipi(
val simpleTagEnd: String = "}}",
val blockStart: String = "#",
val blockEnd: String = "/",
- val globalEnv: Env = Env.basic
+ val globalEnv: Env = Env.Basic
) {
val parse = Parser(
simpleTagStart = simpleTagStart,
Oops, something went wrong.

0 comments on commit 69cebbf

Please sign in to comment.