/scalate-jsp-converter/src/main/scala/org/fusesource/scalate/converter/JspParser.scala

http://github.com/scalate/scalate · Scala · 134 lines · 73 code · 36 blank · 25 comment · 2 complexity · 78491c394889908a71cb0e242a5c9737 MD5 · raw file

  1. /**
  2. * Copyright (C) 2009-2011 the original author or authors.
  3. * See the notice.md file distributed with this work for additional
  4. * information regarding copyright ownership.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.fusesource.scalate.converter
  19. import org.fusesource.scalate.TemplateException
  20. import util.parsing.input.{ Positional, CharSequenceReader, NoPosition, Position }
  21. import org.fusesource.scalate.support.Text
  22. sealed abstract class PageFragment extends Positional {
  23. }
  24. case class QualifiedName(
  25. prefix: String,
  26. name: String) extends Positional {
  27. val qualifiedName = prefix + ":" + name
  28. override def toString = qualifiedName
  29. }
  30. case class Attribute(
  31. name: String,
  32. value: Expression) extends Positional
  33. case class CommentFragment(
  34. comment: Text) extends PageFragment
  35. case class DollarExpressionFragment(
  36. code: Text) extends PageFragment {
  37. val toScala = ExpressionLanguage.asScala(code.toString)
  38. override def toString = "${" + toScala + "}"
  39. }
  40. case class TextFragment(
  41. text: Text) extends PageFragment {
  42. override def toString = text.toString
  43. }
  44. case class Element(
  45. qname: QualifiedName,
  46. attributes: List[Attribute],
  47. body: List[PageFragment]) extends PageFragment {
  48. val qualifiedName = qname.qualifiedName
  49. lazy val attributeMap: Map[String, Expression] = Map(attributes.map(a => a.name -> a.value): _*)
  50. /**
  51. * Returns the mandatory expression for the given attribute name or throw an expression if its not found
  52. */
  53. def attribute(name: String): Expression = attributeMap.get(name) match {
  54. case Some(e) => e
  55. case _ => throw new IllegalArgumentException("No '" + name + "' attribute on tag " + this)
  56. }
  57. }
  58. /**
  59. * Parser of JSP for the purposes of transformation to Scalate; so its not perfect but gives folks a head start
  60. *
  61. * @version $Revision : 1.1 $
  62. */
  63. class JspParser extends MarkupScanner {
  64. protected val expressionParser = new ExpressionParser
  65. private def phraseOrFail[T](p: Parser[T], in: String): T = {
  66. val x = phrase(p)(new CharSequenceReader(in))
  67. x match {
  68. case Success(result, _) => result
  69. case NoSuccess(message, next) => throw new InvalidJspException(message, next.pos);
  70. }
  71. }
  72. def parsePage(in: String) = {
  73. phraseOrFail(page, in)
  74. }
  75. def page = rep(pageFragment)
  76. val pageFragment: Parser[PageFragment] = positioned(markup | expression | textFragment)
  77. val textFragment = upto(markup | expression) ^^ { TextFragment(_) }
  78. def elementTextContent = someUpto(closeElement | markup | expression) ^^ { TextFragment(_) }
  79. def markup: Parser[PageFragment] = element | emptyElement
  80. def emptyElement = (openElement("/>")) ^^ {
  81. case q ~ al => Element(q, al, Nil)
  82. }
  83. def element = (openElement(">") ~ rep(markup | expression | elementTextContent) ~ closeElement) ^^ {
  84. case (q ~ al) ~ b ~ q2 =>
  85. if (q != q2) throw new InvalidJspException("Expected close element of " + q + " but found " + q2, q2.pos)
  86. Element(q, al, b)
  87. }
  88. def qualifiedName: Parser[QualifiedName] = positioned(((IDENT <~ ":") ~ IDENT) ^^ { case p ~ n => QualifiedName(p, n) })
  89. def openElement(end: String) = "<" ~> qualifiedName ~ attributeList <~ end
  90. def closeElement: Parser[QualifiedName] = ("</" ~> qualifiedName) <~ repS ~ ">"
  91. def attributeList = rep(attribute)
  92. def attribute = ((S ~> IDENT <~ repS <~ "=" <~ repS) ~ STRING) ^^ { case n ~ v => Attribute(n, toExpression(v)) }
  93. val expression = wrapped("${", "}") ^^ { DollarExpressionFragment(_) }
  94. def toExpression(text: String) = expressionParser.parseExpression(text)
  95. }
  96. class InvalidJspException(
  97. val brief: String,
  98. val pos: Position = NoPosition) extends TemplateException(brief + " at " + pos)