Commit d45990a6 authored by Stefan Plantikow's avatar Stefan Plantikow
Browse files

Reorganize Pretty trait and Doc helpers

parent 230141d1
Showing with 73 additions and 59 deletions
+73 -59
...@@ -21,9 +21,9 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner ...@@ -21,9 +21,9 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner
import org.neo4j.cypher.InternalException import org.neo4j.cypher.InternalException
import org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans._ import org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans._
import org.neo4j.cypher.internal.compiler.v2_1.pprint.{Pretty, pformat} import org.neo4j.cypher.internal.compiler.v2_1.pprint.{GeneratedPretty, Pretty, pformat}
trait PlannerQuery extends Pretty { trait PlannerQuery extends GeneratedPretty {
def graph: QueryGraph def graph: QueryGraph
def projection: QueryProjection def projection: QueryProjection
def tail: Option[PlannerQuery] def tail: Option[PlannerQuery]
......
...@@ -22,9 +22,9 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner ...@@ -22,9 +22,9 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner
import org.neo4j.cypher.internal.compiler.v2_1.ast._ import org.neo4j.cypher.internal.compiler.v2_1.ast._
import org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans._ import org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans._
import org.neo4j.cypher.internal.compiler.v2_1.helpers.UnNamedNameGenerator.isNamed import org.neo4j.cypher.internal.compiler.v2_1.helpers.UnNamedNameGenerator.isNamed
import org.neo4j.cypher.internal.compiler.v2_1.pprint.{Pretty, pformat} import org.neo4j.cypher.internal.compiler.v2_1.pprint.{GeneratedPretty, Pretty, pformat}
trait QueryGraph extends Pretty { trait QueryGraph extends GeneratedPretty {
def patternRelationships: Set[PatternRelationship] def patternRelationships: Set[PatternRelationship]
def patternNodes: Set[IdName] def patternNodes: Set[IdName]
def argumentIds: Set[IdName] def argumentIds: Set[IdName]
......
...@@ -22,9 +22,9 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner ...@@ -22,9 +22,9 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner
import org.neo4j.cypher.internal.compiler.v2_1.ast.{Identifier, SortItem, Expression} import org.neo4j.cypher.internal.compiler.v2_1.ast.{Identifier, SortItem, Expression}
import org.neo4j.cypher.InternalException import org.neo4j.cypher.InternalException
import org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans.IdName import org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans.IdName
import org.neo4j.cypher.internal.compiler.v2_1.pprint.{Pretty, pformat} import org.neo4j.cypher.internal.compiler.v2_1.pprint.{GeneratedPretty, Pretty, pformat}
trait QueryProjection extends Pretty { trait QueryProjection extends GeneratedPretty {
def projections: Map[String, Expression] def projections: Map[String, Expression]
def sortItems: Seq[SortItem] def sortItems: Seq[SortItem]
def limit: Option[Expression] def limit: Option[Expression]
...@@ -55,7 +55,7 @@ object QueryProjection { ...@@ -55,7 +55,7 @@ object QueryProjection {
} }
case class QueryProjectionImpl(projections: Map[String, Expression], sortItems: Seq[SortItem], limit: Option[Expression], case class QueryProjectionImpl(projections: Map[String, Expression], sortItems: Seq[SortItem], limit: Option[Expression],
skip: Option[Expression]) extends QueryProjection { skip: Option[Expression]) extends QueryProjection {
def withProjections(projections: Map[String, Expression]): QueryProjection = copy(projections = projections) def withProjections(projections: Map[String, Expression]): QueryProjection = copy(projections = projections)
def withSortItems(sortItems: Seq[SortItem]): QueryProjection = copy(sortItems = sortItems) def withSortItems(sortItems: Seq[SortItem]): QueryProjection = copy(sortItems = sortItems)
......
...@@ -22,14 +22,14 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner ...@@ -22,14 +22,14 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner
import org.neo4j.cypher.internal.compiler.v2_1.ast._ import org.neo4j.cypher.internal.compiler.v2_1.ast._
import org.neo4j.helpers.ThisShouldNotHappenError import org.neo4j.helpers.ThisShouldNotHappenError
import org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans.IdName import org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans.IdName
import org.neo4j.cypher.internal.compiler.v2_1.pprint.Pretty import org.neo4j.cypher.internal.compiler.v2_1.pprint.{GeneratedPretty, Pretty}
case class Predicate(dependencies: Set[IdName], exp: Expression) extends Pretty { case class Predicate(dependencies: Set[IdName], exp: Expression) extends GeneratedPretty {
def hasDependenciesMet(symbols: Set[IdName]): Boolean = def hasDependenciesMet(symbols: Set[IdName]): Boolean =
(dependencies -- symbols).isEmpty (dependencies -- symbols).isEmpty
} }
case class Selections(predicates: Set[Predicate] = Set.empty) extends Pretty { case class Selections(predicates: Set[Predicate] = Set.empty) extends GeneratedPretty {
def predicatesGiven(ids: Set[IdName]): Seq[Expression] = predicates.collect { def predicatesGiven(ids: Set[IdName]): Seq[Expression] = predicates.collect {
case p@Predicate(_, predicate) if p.hasDependenciesMet(ids) => predicate case p@Predicate(_, predicate) if p.hasDependenciesMet(ids) => predicate
}.toSeq }.toSeq
......
...@@ -21,7 +21,7 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans ...@@ -21,7 +21,7 @@ package org.neo4j.cypher.internal.compiler.v2_1.planner.logical.plans
import org.neo4j.cypher.internal.compiler.v2_1.ast.RelTypeName import org.neo4j.cypher.internal.compiler.v2_1.ast.RelTypeName
import org.neo4j.graphdb.Direction import org.neo4j.graphdb.Direction
import org.neo4j.cypher.internal.compiler.v2_1.pprint.{Pretty, pformat} import org.neo4j.cypher.internal.compiler.v2_1.pprint.{GeneratedPretty, Pretty, pformat}
/* /*
A LogicalPlan is an algebraic query, which is represented by a query tree whose leaves are database relations and A LogicalPlan is an algebraic query, which is represented by a query tree whose leaves are database relations and
...@@ -29,7 +29,7 @@ non-leaf nodes are algebraic operators like selections, projections, and joins. ...@@ -29,7 +29,7 @@ non-leaf nodes are algebraic operators like selections, projections, and joins.
application of the corresponding operator on the relations generated by its children, the result of which is then sent application of the corresponding operator on the relations generated by its children, the result of which is then sent
further up. Thus, the edges of a tree represent data flow from bottom to top, i.e., from the leaves, which correspond further up. Thus, the edges of a tree represent data flow from bottom to top, i.e., from the leaves, which correspond
to data in the database, to the root, which is the final operator producing the query answer. */ to data in the database, to the root, which is the final operator producing the query answer. */
abstract class LogicalPlan extends Product with Pretty { abstract class LogicalPlan extends Product with GeneratedPretty {
def lhs: Option[LogicalPlan] def lhs: Option[LogicalPlan]
def rhs: Option[LogicalPlan] def rhs: Option[LogicalPlan]
...@@ -44,7 +44,7 @@ abstract class LogicalLeafPlan extends LogicalPlan { ...@@ -44,7 +44,7 @@ abstract class LogicalLeafPlan extends LogicalPlan {
final case class IdName(name: String) extends AnyVal final case class IdName(name: String) extends AnyVal
final case class PatternRelationship(name: IdName, nodes: (IdName, IdName), dir: Direction, types: Seq[RelTypeName], length: PatternLength) final case class PatternRelationship(name: IdName, nodes: (IdName, IdName), dir: Direction, types: Seq[RelTypeName], length: PatternLength)
extends Pretty { extends GeneratedPretty {
def directionRelativeTo(node: IdName): Direction = if (node == left) dir else dir.reverse() def directionRelativeTo(node: IdName): Direction = if (node == left) dir else dir.reverse()
...@@ -57,7 +57,7 @@ final case class PatternRelationship(name: IdName, nodes: (IdName, IdName), dir: ...@@ -57,7 +57,7 @@ final case class PatternRelationship(name: IdName, nodes: (IdName, IdName), dir:
def right = nodes._2 def right = nodes._2
} }
trait PatternLength extends Pretty { trait PatternLength extends GeneratedPretty {
def isSimple: Boolean def isSimple: Boolean
} }
......
...@@ -19,9 +19,7 @@ ...@@ -19,9 +19,7 @@
*/ */
package org.neo4j.cypher.internal.compiler.v2_1.pprint package org.neo4j.cypher.internal.compiler.v2_1.pprint
import org.neo4j.cypher.internal.compiler.v2_1.pprint.impl.LineDocFormatter
import org.neo4j.cypher.internal.compiler.v2_1.pprint.docbuilders.docStructureDocBuilder import org.neo4j.cypher.internal.compiler.v2_1.pprint.docbuilders.docStructureDocBuilder
import scala.text.{DocBreak, DocText, DocCons, Document}
/** /**
* Class of pretty-printable documents. * Class of pretty-printable documents.
...@@ -30,18 +28,20 @@ import scala.text.{DocBreak, DocText, DocCons, Document} ...@@ -30,18 +28,20 @@ import scala.text.{DocBreak, DocText, DocCons, Document}
* (cf. http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.34.2200&rep=rep1&type=pdf) * (cf. http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.34.2200&rep=rep1&type=pdf)
* *
*/ */
sealed abstract class Doc { sealed abstract class Doc extends GeneratedPretty with HasLineFormatter {
import Doc._ import Doc._
override def toString = pformat(this, formatter = LineDocFormatter)(docStructureDocBuilder.docGenerator)
def ::(hd: Doc): Doc = cons(hd, this) def ::(hd: Doc): Doc = cons(hd, this)
def :/:(hd: Doc): Doc = cons(hd, cons(break, this)) def :/:(hd: Doc): Doc = cons(hd, cons(break, this))
def :?:(hd: Doc): Doc = replaceNil(hd, this) def :?:(hd: Doc): Doc = replaceIfNil(hd, this)
def :+:(hd: Doc): Doc = appendWithBreak(hd, this) def :+:(hd: Doc): Doc = appendWithBreak(hd, this)
def isNil = false
def toOption: Option[Doc] = Some(this) def toOption: Option[Doc] = Some(this)
override def docGenerator: DocGenerator[Doc] = docStructureDocBuilder.docGenerator
} }
object Doc { object Doc {
...@@ -50,23 +50,15 @@ object Doc { ...@@ -50,23 +50,15 @@ object Doc {
def cons(head: Doc, tail: Doc = nil): Doc = if (head == nil) tail else ConsDoc(head, tail) def cons(head: Doc, tail: Doc = nil): Doc = if (head == nil) tail else ConsDoc(head, tail)
def nil: Doc = NilDoc def nil: Doc = NilDoc
// replace nil with default document // replace nil tail with default document
def replaceNil(head: Doc, tail: Doc) = tail match { def replaceIfNil(default: Doc, tail: Doc) =
case NilDoc => head if (tail.isNil) default else tail
case other => tail
}
// append doc with breaks but replace away nils // append docs with breaks but remove any nils
def appendWithBreak(head: Doc, tail: Doc) = def appendWithBreak(head: Doc, tail: Doc, break: BreakingDoc = break) =
if (head == nil) if (head.isNil) tail else if (tail.isNil) head else ConsDoc(head, breakBefore(tail, break = break))
tail
else
tail match {
case NilDoc => head
case other => ConsDoc(head, ConsDoc(BreakDoc, other))
}
// unbreakable text doc // unbreakable text doc
...@@ -75,12 +67,15 @@ object Doc { ...@@ -75,12 +67,15 @@ object Doc {
// breaks are either expanded to their value or a line break // breaks are either expanded to their value or a line break
val break: BreakingDoc = BreakDoc val break: BreakingDoc = BreakDoc
val breakHere: BreakingDoc = BreakWith("") val breakSilent: BreakingDoc = BreakWith("")
def breakWith(value: String): BreakingDoc = BreakWith(value) def breakWith(value: String): BreakingDoc = BreakWith(value)
// useful to force a page break if a group is in PageMode and print nothing otherwise // useful to force a page break if a group is in PageMode and print nothing otherwise
def breakBefore(doc: Doc): Doc = if (doc == nil) nil else breakHere :: doc def breakSilentBefore(doc: Doc): Doc = breakBefore(doc, break = breakSilent)
def breakBefore(doc: Doc, break: BreakingDoc = break): Doc =
if (doc.isNil) doc else break :: doc
// *all* breaks in a group are either expanded to their value or a line break // *all* breaks in a group are either expanded to their value or a line break
...@@ -101,7 +96,7 @@ object Doc { ...@@ -101,7 +96,7 @@ object Doc {
// helper // helper
implicit def opt(optDoc: Option[Doc]) = optDoc.getOrElse(NilDoc) implicit def opt(optDoc: Option[Doc]) = optDoc.getOrElse(nil)
implicit def list(docs: TraversableOnce[Doc]): Doc = docs.foldRight(nil)(cons) implicit def list(docs: TraversableOnce[Doc]): Doc = docs.foldRight(nil)(cons)
...@@ -110,11 +105,6 @@ object Doc { ...@@ -110,11 +105,6 @@ object Doc {
case (hd, tail) => hd :: break :: tail case (hd, tail) => hd :: break :: tail
} }
def breakBeforeList(docs: TraversableOnce[Doc]): Doc = docs.foldRight(nil) {
case (hd, NilDoc) => hd :: nil
case (hd, tail) => hd :: breakBefore(tail)
}
def sepList(docs: TraversableOnce[Doc], sep: Doc = ",", break: BreakingDoc = break): Doc = docs.foldRight(nil) { def sepList(docs: TraversableOnce[Doc], sep: Doc = ",", break: BreakingDoc = break): Doc = docs.foldRight(nil) {
case (hd, NilDoc) => hd :: nil case (hd, NilDoc) => hd :: nil
case (hd, tail) => hd :: sep :: break :: tail case (hd, tail) => hd :: sep :: break :: tail
...@@ -124,20 +114,19 @@ object Doc { ...@@ -124,20 +114,19 @@ object Doc {
group( group(
name :: name ::
open :: open ::
nest(group(breakBefore(innerDoc))) :: nest(group(breakSilentBefore(innerDoc))) ::
breakBefore(close) breakSilentBefore(close)
) )
def section(start: Doc, inner: Doc): Doc = inner match { def section(start: Doc, inner: Doc, break: BreakingDoc = break): Doc =
case NilDoc => nil if (inner.isNil) inner else group(start :: nest(breakBefore(inner, break = break)))
case _ => group(start :: nest(nil :/: inner))
}
} }
final case class ConsDoc(head: Doc, tail: Doc = NilDoc) extends Doc final case class ConsDoc(head: Doc, tail: Doc = NilDoc) extends Doc
case object NilDoc extends Doc { case object NilDoc extends Doc {
override def toOption = None override def toOption = None
override def isNil = true
} }
sealed abstract class ValueDoc extends Doc { sealed abstract class ValueDoc extends Doc {
...@@ -175,9 +164,8 @@ final case class NestWith(indent: Int, content: Doc) extends NestingDoc { ...@@ -175,9 +164,8 @@ final case class NestWith(indent: Int, content: Doc) extends NestingDoc {
def optIndent = Some(indent) def optIndent = Some(indent)
} }
final case class DocLiteral(doc: Doc) { final case class DocLiteral(doc: Doc) extends PlainlyPretty {
override def toString = override def toDoc = docStructureDocBuilder.docGenerator(doc)
pformat(doc, formatter = DocFormatters.defaultLineFormatter)(docStructureDocBuilder.docGenerator)
} }
...@@ -27,6 +27,8 @@ object DocFormatters { ...@@ -27,6 +27,8 @@ object DocFormatters {
val defaultLineFormatter = LineDocFormatter val defaultLineFormatter = LineDocFormatter
val defaultPageFormatter = PageDocFormatter(defaultLineWidth) val defaultPageFormatter = PageDocFormatter(defaultLineWidth)
val defaultFormatter = defaultPageFormatter
def pageFormatter(lineWidth: Int = defaultLineWidth) = def pageFormatter(lineWidth: Int = defaultLineWidth) =
if (lineWidth == defaultLineWidth) defaultPageFormatter else PageDocFormatter(lineWidth) if (lineWidth == defaultLineWidth) defaultPageFormatter else PageDocFormatter(lineWidth)
} }
...@@ -22,15 +22,39 @@ package org.neo4j.cypher.internal.compiler.v2_1.pprint ...@@ -22,15 +22,39 @@ package org.neo4j.cypher.internal.compiler.v2_1.pprint
import org.neo4j.cypher.internal.compiler.v2_1.pprint.docbuilders.defaultDocBuilder import org.neo4j.cypher.internal.compiler.v2_1.pprint.docbuilders.defaultDocBuilder
trait Pretty { trait Pretty {
def toDoc: Doc
def toDoc = docGenerator(this) def format(docFormatter: DocFormatter)
(implicit docGenerator: DocGenerator[this.type]) =
pformat(this, docFormatter)
}
trait HasFormatter {
def docFormatter: DocFormatter = DocFormatters.defaultFormatter
}
trait HasLineFormatter extends HasFormatter {
override def docFormatter: DocFormatter = DocFormatters.defaultLineFormatter
}
override def toString = format() trait HasPageFormatter extends HasFormatter {
override def docFormatter: DocFormatter = DocFormatters.defaultPageFormatter
}
trait PlainlyPretty extends Pretty with HasFormatter {
override def toString = printToString(docFormatter(toDoc))
override def format(docFormatter: DocFormatter = docFormatter)
(implicit docGenerator: DocGenerator[this.type]) =
super.format(docFormatter)
}
def format(docFormatter: DocFormatter = docFormatter) trait GeneratedPretty extends Pretty with HasFormatter {
def toDoc = docGenerator(this)
override def format(docFormatter: DocFormatter = docFormatter)
(implicit docGenerator: DocGenerator[this.type] = docGenerator) = (implicit docGenerator: DocGenerator[this.type] = docGenerator) =
pformat(this, docFormatter) super.format(docFormatter)
def docGenerator: DocGenerator[this.type] = defaultDocBuilder.docGenerator def docGenerator: DocGenerator[this.type] = defaultDocBuilder.docGenerator
def docFormatter: DocFormatter = DocFormatters.defaultPageFormatter
} }
...@@ -43,7 +43,7 @@ case object astExpressionDocBuilder extends CachingDocBuilder[Any] { ...@@ -43,7 +43,7 @@ case object astExpressionDocBuilder extends CachingDocBuilder[Any] {
":" :: name ":" :: name
case HasLabels(expr, labels) => (inner) => case HasLabels(expr, labels) => (inner) =>
inner(expr) :: breakBeforeList(labels.map(inner)) inner(expr) :: breakList(labels.map(inner), break = breakSilent)
case Not(expr) => (inner) => case Not(expr) => (inner) =>
"NOT" :/: inner(expr) "NOT" :/: inner(expr)
......
...@@ -38,7 +38,7 @@ object logicalPlanDocBuilder extends CachingDocBuilder[Any] { ...@@ -38,7 +38,7 @@ object logicalPlanDocBuilder extends CachingDocBuilder[Any] {
.filter( (v: Any) => !childPlans.contains(v) ) .filter( (v: Any) => !childPlans.contains(v) )
.map(inner) .map(inner)
val deps = sepList(plan.availableSymbols.map(inner), break = breakHere) val deps = sepList(plan.availableSymbols.map(inner), break = breakSilent)
val depsBlock = block(plan.productPrefix, open = "[", close = "]")(deps) val depsBlock = block(plan.productPrefix, open = "[", close = "]")(deps)
val head = block(depsBlock)(sepList(arguments)) val head = block(depsBlock)(sepList(arguments))
......
...@@ -57,7 +57,7 @@ case object plannerDocBuilder extends DocBuilderChain[Any] { ...@@ -57,7 +57,7 @@ case object plannerDocBuilder extends DocBuilderChain[Any] {
val forNestedPredicate = asDocBuilder[Any] { val forNestedPredicate = asDocBuilder[Any] {
case Predicate(dependencies, expr) => (inner) => case Predicate(dependencies, expr) => (inner) =>
val pred = sepList(dependencies.map(inner), break = breakHere) val pred = sepList(dependencies.map(inner), break = breakSilent)
val predBlock = block("Predicate", open = "[", close = "]")(pred) val predBlock = block("Predicate", open = "[", close = "]")(pred)
block(predBlock)(inner(expr)) block(predBlock)(inner(expr))
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment