Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import scala.util.parsing.combinator._;
- import TextStyle._, HAlign._, VAlign._
- object ConstMatcher {
- def CtoInt (s:String) = s.toInt
- def CtoBoolean (s:String) = s.toBoolean
- def CtoString (s:String) = s.substring(1,s.length-1)
- def CtoColor (s:String) = new Color(s)
- def CtoId (s:String) = s
- def CtoTextStyle (s:String) = TextStyle.withName(s)
- def CtoHAlign (s:String) = HAlign.withName(s)
- def CtoVAlign (s:String) = VAlign.withName(s)
- }
- import ConstMatcher._
- object LayoutParser extends JavaTokenParsers {
- val reservedwords = List("true","false","otherwise")
- val reservedwordsregex = reservedwords.mkString("|")
- // Helper Function
- def customFilter[T](pre:String, elems:List[~[String,T]]):List[T] = {
- var a:List[T] = Nil
- for (elem <- elems)
- if (elem._1.equals(pre)) a = elem._2 :: a
- return a
- }
- // Identifier for variable and properties of variables
- def Var: Parser[DirectExpr] = {
- // In order to avoid identifying reserved words as variables, use the
- // guard parser which does not consume input
- not(guard(reservedwordsregex.r))~>ident~(("." ~> ident)?) ^^ {
- case loc~Some(prop) => new PropVar(loc,prop)
- case id~None => new Var(id)
- }
- }
- // ***************************************************************************
- // Numerical Expressions
- // ***************************************************************************
- def NumExpr: Parser[DirectExpr] = Sum
- def Sum: Parser[DirectExpr] = {
- (Prod ~ rep("+" ~ Prod | "-" ~ Prod)) ^^ {
- case a ~ Nil => a
- case a ~ b => new Sum(a::customFilter("+", b),customFilter("-", b))
- }
- }
- def Prod: Parser[DirectExpr] = {
- (NumElem ~ rep("*" ~ NumElem | "/" ~ NumElem)) ^^ {
- case a ~ Nil => a
- case a ~ b => new Prod(a::customFilter("*", b), customFilter("/", b))
- }
- }
- def NumConst: Parser[Literal[Int]] = {
- floatingPointNumber ^^ { str => new Literal(CtoInt(str)) }
- }
- def NumElem: Parser[DirectExpr] = {
- NumConst | ("("~>NumExpr<~")") | Var
- }
- // ***************************************************************************
- // Boolean Expressions
- // ***************************************************************************
- // TODO: In our implementation we allow only to do comparision between numbers
- // and booleans, so to allow more comparisions change NonBoolComparable
- // to include other elements
- // WARNING: Using things which may have '=' in them or be mapped back to a
- // boolean, or a list of other case will cause infinite recursion
- // when parsing (-> Stack Overflow) so generally don't touch unless
- // you know what you are doing
- def NonBoolComparable = NumExpr
- def BoolExpr: Parser[DirectExpr] = Disnj
- def Disnj: Parser[DirectExpr] = {
- (Conj ~ rep("||" ~ Conj)) ^^ {
- case a ~ Nil => a
- case a ~ b => new Disnj(a::customFilter("||", b))
- }
- }
- def Conj: Parser[DirectExpr] = {
- (BoolComp ~ rep("&&" ~ BoolComp)) ^^ {
- case a ~ Nil => a
- case a ~ b => new Conj(a::customFilter("&&", b))
- }
- }
- // Remember: comparision has the highest precedence from all boolean operators
- def BoolComp: Parser[DirectExpr] = {
- (BoolElem ~ (("="~>BoolElem)?)) ^^ {
- case a ~ None => a
- case a ~ Some(b) => new Comp(a,b)
- }
- }
- def NonBoolComp: Parser[DirectExpr] = {
- (NonBoolComparable~"="~NonBoolComparable) ^^ { case e1~"="~e2 => new Comp(e1,e2) }
- }
- def BoolConst: Parser[Literal[Boolean]] = {
- ("true" | "false") ^^ { str => new Literal(CtoBoolean(str))}
- }
- def BoolElem: Parser[DirectExpr] = {
- BoolConst | ("("~>BoolExpr<~")") | Var ||| NonBoolComp
- }
- // ***************************************************************************
- // String Expressions
- // ***************************************************************************
- def StringConst: Parser[Literal[String]] = {
- stringLiteral ^^ { str => new Literal(CtoString(str)) }
- }
- def StringElem: Parser[DirectExpr] = {
- StringConst | "("~>StringExpr<~")" | Var
- }
- def StringExpr: Parser[DirectExpr] = {
- StringElem
- }
- // ***************************************************************************
- // Color Expressions
- // ***************************************************************************
- def ColorConst: Parser[Literal[Color]] = {
- "0x[0-9A-Fa-f]{6}".r ^^ { str => new Literal(CtoColor(str)) }
- }
- def ColorElem: Parser[DirectExpr] = {
- ColorConst | "("~>ColorExpr<~")" | Var
- }
- def ColorExpr: Parser[DirectExpr] = {
- ColorElem
- }
- // ***************************************************************************
- // Font Expressions
- // ***************************************************************************
- def FontConst: Parser[Literal[Font]] = {
- ("("~StringConst~","~NumConst~","~("bold" | "italic" | "regular")~")") ^^ {
- case "("~face~","~num~","~style~")" => new Literal(new Font(face.value,num.value,CtoTextStyle(style)))
- }
- }
- def FontElem: Parser[DirectExpr] = {
- FontConst | "("~>FontExpr<~")" | Var
- }
- def FontExpr: Parser[DirectExpr] = {
- FontElem
- }
- // ***************************************************************************
- // HAlign Expressions
- // ***************************************************************************
- def HAlignConst: Parser[Literal[HAlign]] = {
- ("left" | "center" | "right") ^^ { str => new Literal(CtoHAlign(str))}
- }
- def HAlignElem: Parser[DirectExpr] = {
- HAlignConst | "("~>HAlignExpr<~")" | Var
- }
- def HAlignExpr: Parser[DirectExpr] = {
- HAlignElem
- }
- // ***************************************************************************
- // VAlign Expressions
- // ***************************************************************************
- def VAlignConst: Parser[Literal[VAlign]] = {
- ("top" | "middle" | "bottom") ^^ { str => new Literal(CtoVAlign(str))}
- }
- def VAlignElem: Parser[DirectExpr] = {
- VAlignConst | "("~>VAlignExpr<~")" | Var
- }
- def VAlignExpr: Parser[DirectExpr] = {
- VAlignElem
- }
- // ***************************************************************************
- // Conditional Expressions
- // ***************************************************************************
- // TODO: If you want to allow nested conditions (yuck!)
- // replace DirectExpr by Expr here
- def CondBody = DirectExpr
- def SimpleCond: Parser[(Expr,Expr)] = {
- (BoolExpr~"=>"~CondBody) ^^ {case bool~"=>"~expr => (bool,expr)}
- }
- def OtherwiseCond: Parser[Expr] = {
- "otherwise"~>":"~>CondBody
- }
- def CondExpr: Parser[Expr] = {
- ("{"~>rep1(SimpleCond<~",")~OtherwiseCond<~"}") ^^ { case conds~o => new Cond(conds,o) }
- }
- // ***************************************************************************
- // All available Expressions
- // ***************************************************************************
- def DirectExpr = (NumExpr ||| BoolExpr) | StringExpr | ColorExpr | FontExpr | HAlignExpr | VAlignExpr
- def Expr = DirectExpr | CondExpr
- // ***************************************************************************
- // Widget Layout Expressions
- // Note that in order to wrap a widget in a "panel" for specifying size limits
- // or properties, the existing widget must again be wrapped in braces!
- // ***************************************************************************
- def Layout = Hgroup
- def Vgroup: Parser[Widget] = {
- (Hgroup ~ rep("---" ~> Hgroup)) ^^ {
- case a ~ Nil => a
- case a ~ b => new HVContainer(a::b, true)
- }
- }
- def Hgroup: Parser[Widget] = {
- (Widget ~ rep("|" ~> Widget)) ^^ {
- case a ~ Nil => a
- case a ~ b => new HVContainer(a::b, false)
- }
- }
- def Widget: Parser[Widget] = {
- (AtomicWidget
- | (("("~Layout~")"~SizeOpt~PropListOpt) ^^ {
- case "("~w~")"~size~props =>
- // If we had an empty wrapping, or if was just the braces, in both
- // cases the if will be true and we can ommit the wrapping as junk
- if (props.isEmpty && size == (None,None)) w
- else new OneContainer(w,size._1,size._2,props)
- })
- )
- }
- def Dim: Parser[Option[DirectExpr]] = {
- ((floatingPointNumber ^^ { str => Some(new Literal(CtoInt(str)))})
- | (("("~>NumExpr<~")") ^^ { ne => Some(ne) })
- | ("?" ^^ { s => None})
- )
- }
- def Size: Parser[(Option[DirectExpr],Option[DirectExpr])] = {
- (":" ~ Dim ~ "x" ~ Dim) ^^ { case ":" ~ w ~ "x" ~ h => (w,h) }
- }
- def SizeOpt: Parser[(Option[DirectExpr],Option[DirectExpr])] = {
- ((Size?) ^^ { case None => (None,None); case Some(size) => size})
- }
- def Prop: Parser[(String,Expr)] = {
- (ident~"="~Expr) ^^ { case id~"="~expr => (id,expr) }
- }
- def PropList: Parser[Map[String,Expr]] = {
- ("["~>rep1sep(Prop,",")<~"]") ^^ { props => Map(props :_*)}
- }
- def PropListOpt: Parser[Map[String,Expr]] = {
- ((PropList?) ^^ { case None => Map[String,Expr](); case Some(props) => props })
- }
- def AtomicWidget: Parser[Widget] = {
- ("("~((ident?) ^^ { case None => ""; case Some(str) => str})
- ~SizeOpt~")"~PropListOpt) ^^ {
- case "("~id~size~")"~props => new AtomicWidget(id,size._1,size._2,props)
- }
- }
- // ***************************************************************************
- // Layout Definitions - Program Expressions
- // ***************************************************************************
- def Layoutdef: Parser[(String,Widget)] = {
- (ident~"<-"~Layout) ^^ { case id~"<-"~w => (id,w) }
- }
- def Program = Layoutdef*
- def iParse(input:String) = parseAll(Program,input)
- def main(args:Array[String]) {
- var s = new java.util.Scanner(System.in)
- while (true) {
- print ("Enter Input: ")
- val line = s.nextLine();
- if (line.equals("quit")) return
- iParse(line) match {
- case Success(result, _) => println ("Result: "); result map println;
- case _ => println("Could not parse the input string.")
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment