PageRenderTime 21ms CodeModel.GetById 6ms app.highlight 11ms RepoModel.GetById 2ms app.codeStats 0ms

/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 */
 18package org.fusesource.scalate.converter
 19
 20import org.fusesource.scalate.TemplateException
 21import util.parsing.input.{ Positional, CharSequenceReader, NoPosition, Position }
 22import org.fusesource.scalate.support.Text
 23
 24sealed abstract class PageFragment extends Positional {
 25}
 26
 27case class QualifiedName(
 28  prefix: String,
 29  name: String) extends Positional {
 30
 31  val qualifiedName = prefix + ":" + name
 32
 33  override def toString = qualifiedName
 34}
 35
 36case class Attribute(
 37  name: String,
 38  value: Expression) extends Positional
 39
 40case class CommentFragment(
 41  comment: Text) extends PageFragment
 42
 43case class DollarExpressionFragment(
 44  code: Text) extends PageFragment {
 45
 46  val toScala = ExpressionLanguage.asScala(code.toString)
 47
 48  override def toString = "${" + toScala + "}"
 49}
 50
 51case class TextFragment(
 52  text: Text) extends PageFragment {
 53
 54  override def toString = text.toString
 55
 56}
 57
 58case class Element(
 59  qname: QualifiedName,
 60  attributes: List[Attribute],
 61  body: List[PageFragment]) extends PageFragment {
 62
 63  val qualifiedName = qname.qualifiedName
 64
 65  lazy val attributeMap: Map[String, Expression] = Map(attributes.map(a => a.name -> a.value): _*)
 66
 67  /**
 68   * Returns the mandatory expression for the given attribute name or throw an expression if its not found
 69   */
 70  def attribute(name: String): Expression = attributeMap.get(name) match {
 71    case Some(e) => e
 72    case _ => throw new IllegalArgumentException("No '" + name + "' attribute on tag " + this)
 73  }
 74}
 75
 76/**
 77 * Parser of JSP for the purposes of transformation to Scalate; so its not perfect but gives folks a head start
 78 *
 79 * @version $Revision : 1.1 $
 80 */
 81class JspParser extends MarkupScanner {
 82
 83  protected val expressionParser = new ExpressionParser
 84
 85  private def phraseOrFail[T](p: Parser[T], in: String): T = {
 86    val x = phrase(p)(new CharSequenceReader(in))
 87    x match {
 88      case Success(result, _) => result
 89      case NoSuccess(message, next) => throw new InvalidJspException(message, next.pos);
 90    }
 91  }
 92
 93  def parsePage(in: String) = {
 94    phraseOrFail(page, in)
 95  }
 96
 97  def page = rep(pageFragment)
 98
 99  val pageFragment: Parser[PageFragment] = positioned(markup | expression | textFragment)
100
101  val textFragment = upto(markup | expression) ^^ { TextFragment(_) }
102
103  def elementTextContent = someUpto(closeElement | markup | expression) ^^ { TextFragment(_) }
104
105  def markup: Parser[PageFragment] = element | emptyElement
106
107  def emptyElement = (openElement("/>")) ^^ {
108    case q ~ al => Element(q, al, Nil)
109  }
110
111  def element = (openElement(">") ~ rep(markup | expression | elementTextContent) ~ closeElement) ^^ {
112    case (q ~ al) ~ b ~ q2 =>
113      if (q != q2) throw new InvalidJspException("Expected close element of " + q + " but found " + q2, q2.pos)
114      Element(q, al, b)
115  }
116
117  def qualifiedName: Parser[QualifiedName] = positioned(((IDENT <~ ":") ~ IDENT) ^^ { case p ~ n => QualifiedName(p, n) })
118
119  def openElement(end: String) = "<" ~> qualifiedName ~ attributeList <~ end
120
121  def closeElement: Parser[QualifiedName] = ("</" ~> qualifiedName) <~ repS ~ ">"
122
123  def attributeList = rep(attribute)
124
125  def attribute = ((S ~> IDENT <~ repS <~ "=" <~ repS) ~ STRING) ^^ { case n ~ v => Attribute(n, toExpression(v)) }
126
127  val expression = wrapped("${", "}") ^^ { DollarExpressionFragment(_) }
128
129  def toExpression(text: String) = expressionParser.parseExpression(text)
130}
131
132class InvalidJspException(
133  val brief: String,
134  val pos: Position = NoPosition) extends TemplateException(brief + " at " + pos)