LightningIsMyName

Workshop Parser

Apr 22nd, 2011
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 10.50 KB | None | 0 0
  1. /*
  2.  * To change this template, choose Tools | Templates
  3.  * and open the template in the editor.
  4.  */
  5. //import scala.util.parsing.combinator.syntactical._;
  6. import scala.util.matching.Regex
  7. import scala.util.parsing.combinator._;
  8.  
  9. object TextStyle extends Enumeration {
  10.   type TextStyle = Value;
  11.   val bold, italic, regular = Value;
  12. }
  13.  
  14. object HAlign extends Enumeration {
  15.   type HAlign = Value;
  16.   val left, center, right = Value;
  17. }
  18.  
  19. object VAlign extends Enumeration {
  20.   type VAlign = Value;
  21.   val top, middle, bottom = Value;
  22. }
  23.  
  24. object BinOp extends Enumeration {
  25.   type BinOp = Value;
  26.   val *, -, +, /, ||, && = Value;
  27. }
  28.  
  29. object UnOp extends Enumeration {
  30.   type UnOp = Value;
  31.   val !, - = Value;
  32. }
  33.  
  34. import TextStyle._, HAlign._, VAlign._, BinOp._, UnOp._
  35.  
  36. class Color(hexa:String) {
  37.   assume(hexa.length == 8 && hexa.startsWith("0x"), "Invalid Color Format " + hexa)
  38.   val red = hexa.substring(2,4).toInt
  39.   val green = hexa.substring(4,6).toInt
  40.   val blue = hexa.substring(6,8).toInt
  41. }
  42.  
  43. trait Dim
  44. case object AutoSize extends Dim
  45.  
  46. /* TODO: currently we don't support conditional sizes and this *may* require
  47.  *       changes. Anyway, when traversing the AST simply make sure that the
  48.  *       Expr is a Dim */
  49. trait Expr
  50. trait DirectExpr extends Expr with Dim /* Anything but conditions */
  51. case class Literal(value:Any, init:Boolean) extends DirectExpr
  52. case class Var(id:String) extends DirectExpr
  53. case class PropVar(loc:String, id:String) extends DirectExpr
  54. case class BinaryOp(left:Expr, op:BinOp, right:Expr) extends DirectExpr
  55. case class UnaryOp(op:UnOp, e:Expr) extends DirectExpr
  56. case class Font(size:Int, face:String, style:TextStyle) extends DirectExpr
  57. case class Cond(conds:List[(Expr,Expr)], otherwise:Expr) extends Expr
  58.  
  59. trait Widget {
  60.   def kind(): String
  61.   def properties(): Map[String,Expr]
  62.   def width(): Dim
  63.   def height(): Dim
  64.   def hasChildren (): Boolean
  65.   def getChildren (): Iterable[Widget]
  66. }
  67.  
  68. abstract class WidgetImp(k:String, w:Dim,h:Dim,p:Map[String,Expr],hc:Boolean,gc:Iterable[Widget]) extends Widget {
  69.   def kind = k
  70.   def properties = p
  71.   def width = w
  72.   def height = h
  73.   def hasChildren = hc
  74.   def getChildren = gc
  75. }
  76.  
  77. /* An atomic widget is either one of the built in widgets, or one which was defined
  78.  * as a "subprogram" somewhere else
  79.  * Note that for the empty widget, we will use the empty string as it's kind
  80.  */
  81. class AtomicWidget(k:String, w:Dim,h:Dim,p:Map[String,Expr])
  82.   extends WidgetImp(k,w,h,p,false,List())
  83.  
  84. class HVContainer(ws:List[Widget], isVertical:Boolean)
  85.   extends WidgetImp(if (isVertical) "---" else "|", AutoSize, AutoSize, Map(), true, ws)
  86.  
  87. class OneContainer(ws:Widget, w:Dim, h:Dim, p:Map[String,Expr])
  88.   extends WidgetImp("@", w, h, p, true, List(ws))
  89.  
  90. object ConstMatcher {
  91.   val IntPattern = "[0-9]+"
  92.   val BooleanPattern = "(true)|(false)"
  93.   /* A tricky one! This should look like
  94.    * "(([^"]|(\\"))*)"
  95.    * Which means
  96.    * 1. start with a quote
  97.    * 2. Repeat(non-quote OR (slash quote))
  98.    * 3. End with a quote
  99.    * Note that in order to specify the backslash, we need 2 backslashes!
  100.    */
  101.   val StringPattern = "\"(([^\"]|(\\\\\"))*)\""
  102.   val ColorPattern = "0x[A-Fa-f0-9]{6}"
  103.   val IdPattern = "[A-Za-z_][A-Za-z0-9_]*"
  104.   val TextStylePattern = "(bold)|(italic)|(regular)"
  105.   val HAlignPattern = "(top)|(middle)|(bottom)"
  106.   val VAlignPattern = "(left)|(center)|(right)"
  107.   val BinaryOpPattern = "(\\|\\|)|(&&)|[\\Q+-/*\\E]"
  108.   val UnaryOpPattern = "!|-"
  109.  
  110.   def isInt (s:String) = s.matches(IntPattern)
  111.   def isBoolean (s:String) = s.equals(BooleanPattern)
  112.   def isString (s:String) = s.matches(StringPattern)
  113.   def isColor (s:String) = s.matches(ColorPattern)
  114.   def isId (s:String) = s.matches(IdPattern)
  115.   def isTextStyle (s:String) = s.matches(TextStylePattern)
  116.   def isHAlign (s:String) = s.matches(HAlignPattern)
  117.   def isVAlign (s:String) = s.matches(VAlignPattern)
  118.   def isBinaryOp (s:String) = s.matches(BinaryOpPattern)
  119.   def isUnaryOp (s:String) = s.matches(UnaryOpPattern)
  120.  
  121.   def CtoInt (s:String) = s.toInt
  122.   def CtoBoolean (s:String) = s.toBoolean
  123.   def CtoString (s:String) = s.substring(1,s.length-1)
  124.   def CtoColor (s:String) = new Color(s)
  125.   def CtoId (s:String) = s
  126.   def CtoTextStyle (s:String) = TextStyle.withName(s)
  127.   def CtoHAlign (s:String) = HAlign.withName(s)
  128.   def CtoVAlign (s:String) = VAlign.withName(s)
  129.   def CtoBinaryOp (s:String) = BinOp.withName(s)
  130.   def CtoUnaryOp (s:String) = UnOp.withName(s)
  131. }
  132.  
  133. import ConstMatcher._
  134.  
  135. class ExprParser extends RegexParsers {
  136.   def rr(pat:String) = regex(new Regex(pat))
  137.  
  138.   def pNumericConst = rr(IntPattern)
  139.   def pStringConst = rr(StringPattern)
  140.   def pColorConst = rr(ColorPattern)
  141.   def pId = rr(IdPattern)// ^^ { id => new Var(id) }
  142.   def pBooleanConst = rr(BooleanPattern)
  143.   def pTextStyleConst = rr(TextStylePattern)
  144.   def pHAlignConst = rr(HAlignPattern)
  145.   def pVAlignConst = rr(VAlignPattern)
  146.  
  147.   def pExpr = pCondExpr | pDirectExpr | pInitLiteral | pFontExpr
  148.  
  149.   def pFontExpr = ("(" ~ pNumericConst ~ "," ~ pStringConst ~ "," ~ pTextStyleConst ~ ")") ^^ {case "(" ~ si ~ "," ~ fa ~ "," ~ st ~ ")" => new Font (CtoInt(si),CtoString(fa),CtoTextStyle(st)) }
  150.  
  151.   def pBinop = rr(BinaryOpPattern)
  152.   def pUnop = rr(UnaryOpPattern)
  153.   def pDirectExpr:Parser[DirectExpr]  = (pLiteral
  154.                       | (pId ^^ { name => new Var(name) })
  155.                       | ((pDirectExpr ~ pBinop ~ pDirectExpr) ^^ { case l ~ op ~ r => new BinaryOp(l,CtoBinaryOp(op),r) })
  156.                       | ((pUnop ~ pDirectExpr) ^^  { case op ~ v => new UnaryOp(CtoUnaryOp(op),v) })
  157.                       | ("(" ~> pDirectExpr <~ ")")
  158.                       | ((pId ~ "." ~ pId) ^^ { case l ~ "." ~ p => new PropVar(l,p)}))
  159.  
  160.  
  161.   def pInitLiteral = "?" ~> "(" ~> pLiteral <~ ")" ^^ { lt => new Literal(lt.value,true)}
  162.  
  163.   def pCond = (pDirectExpr ~ "=>" ~ pDirectExpr ~ ",") ^^ {case e1 ~ "=>" ~ e2 ~ "," => (e1,e2)}
  164.   def pCondExpr = ("{" ~ (pCond *) ~ "otherwise" ~ pDirectExpr ~ "}") ^^ {case "{" ~ cnds ~ "otherwise" ~ o ~ "}" => new Cond(cnds,o)}
  165.  
  166.   def pLiteral = ((pNumericConst ^^ { numstr => new Literal(CtoInt(numstr), false) })
  167.                   | (pStringConst ^^ { sstr => new Literal(CtoString(sstr), false) })
  168.                   | (pBooleanConst ^^ { cb => new Literal(CtoBoolean(cb), false) })
  169.                   | (pColorConst ^^ { cstr => new Literal(CtoColor(cstr), false) })
  170.                   | (pHAlignConst ^^ { ha => new Literal(CtoHAlign(ha), false) })
  171.                   | (pVAlignConst ^^ { va => new Literal(CtoVAlign(va), false) })
  172.                   | (pTextStyleConst ^^ { ts => new Literal(CtoTextStyle(ts), false) }))
  173.  
  174. }
  175.  
  176. object GuiParserNew extends /* StandardTokenParsers */ ExprParser {
  177.  
  178.   /* TODO: correct me! */
  179.   def expandMacro (w:Widget, index:String, start:Int, end:Int):List[Widget] = {
  180.     var ws:Array[Widget] = new Array[Widget](end-start+1)
  181.     for (i <- start to end) { /* Includes last index */
  182.       ws(i-start) = w /* TODO - add macro defs and different index each time */
  183.     }
  184.     return ws.toList
  185.   }
  186.  
  187.   /* A program is composed of many widgets definitions */
  188.   def Program:Parser[List[(String,Widget)]] = (WidgetSpec /* | LinearProgramSpec */) *
  189.  
  190.   /* TODO!! */
  191.   def LinearProgramSpec = "long ! and @ random # string $ that % should ^ never & appear"
  192.  
  193.  
  194.   /* Each definition is made of a name and a widget */
  195.   def WidgetSpec:Parser[(String,Widget)] = {
  196.     (pId ~ "<-" ~ pWidget) ^^ { case id ~ "<-" ~ w => id -> w }
  197.   }
  198.  
  199.   /* Each widget is either atomic, or vertical/horizontal composition of several
  200.    * other widgets
  201.    * FIXME - precedence
  202.    */
  203.   def pWidget:Parser[Widget] = {
  204.      (pAtomicWidget
  205.      | (rep1sep (pWidget, "|")             ^^ { ls => new HVContainer (ls, false) })
  206.      | (rep1sep (pWidget, "---")         ^^ { ls => new HVContainer (ls, true) })
  207.      | ((pWidget ~  "*|*"  ~ pRangeSpec) ^^ { case w ~  "*|*"  ~ rs => new HVContainer(expandMacro(w, rs._1, rs._2, rs._3), false)} )
  208.      | ((pWidget ~ "*---*" ~ pRangeSpec) ^^ { case w ~  "*---*"  ~ rs => new HVContainer(expandMacro(w, rs._1, rs._2, rs._3), true)} )
  209.      | ((("(" ~> pWidget <~ ")") ~ (pWidgetSizeDef ?) ~ (pWidgetPropList ?)) ^^ {
  210.           case w ~ None ~ None         => w
  211.           case w ~ Some(sd) ~ None     => new OneContainer(w, sd._1, sd._2, Map())
  212.           case w ~ None ~ Some(pl)     => new OneContainer(w, AutoSize, AutoSize, Map(pl :_*))
  213.           case w ~ Some(sd) ~ Some(pl) => new OneContainer(w, sd._1, sd._2, Map(pl :_*))
  214.         }))
  215.   }
  216.  
  217.   /* When duplication widgets by iteration, their iteration range will look like
  218.    * this */
  219.   def pRangeSpec:Parser[(String,Int,Int)] = {
  220.     (pId ~ "=" ~ pNumericConst ~ ":" ~ pNumericConst) ^^ { case id ~ "=" ~ s ~ ":" ~ e => (id, s.toInt, e.toInt) }
  221.   }
  222.  
  223.   // WidgetDim ::= "?" | NumericConst | "(" DirectExpr ")"
  224.   def pWidgetDim:Parser[Dim] = {
  225.       ((pNumericConst ^^ { num => new Literal(CtoInt(num), false) })
  226.        | ("?"         ^^ { d => AutoSize })
  227.        | ("(" ~> pDirectExpr <~ ")"))
  228.     }
  229.  
  230.   // WidgetSizeDef ::= ":" Dimnsion "x" Dimension
  231.   def pWidgetSizeDef:Parser[(Dim,Dim)] = {
  232.     ":" ~> ((pWidgetDim ~ "x" ~ pWidgetDim) ^^ { case w ~ "x" ~ h => (w,h) })
  233.   }
  234.  
  235.   // WidgetType ::= Id | ""
  236.   def pWidgetType = pId ||| ""
  237.  
  238.   // WidgetDef ::= "(" WidgetType WidgetSizeDef ? ")"
  239.   def pAtomicWidgetDef:Parser[(String,Dim,Dim)] = {
  240.       "(" ~> ((pWidgetType ~ ((":" ~> pWidgetSizeDef) ?)) ^^ { case t ~ Some(n) => (t,n._1,n._2)
  241.                                                                case t ~ None    => (t,AutoSize,AutoSize)}) <~ ")"
  242.   }
  243.  
  244.   // WidgetProp ::= Id "=" Expr
  245.   def pWidgetProp:Parser[(String,Expr)] = (pId ~ "=" ~ pExpr) ^^ {case id ~ "=" ~ expr => (id,expr)}
  246.  
  247.   // WidgetPropList ::= "[" WidgetProp * "]"
  248.   def pWidgetPropList:Parser[List[(String,Expr)]] = {
  249.     "[" ~> (pWidgetProp *)  <~ "]"
  250.   }
  251.  
  252.   // AtomicWidget ::= AtomicWidgetDef pWidgetPropList ?
  253.   def pAtomicWidget:Parser[AtomicWidget] = {
  254.     (pAtomicWidgetDef ~ (pWidgetPropList ?) ^^ { case w ~ None => new AtomicWidget(w._1,w._2,w._3,Map())
  255.                                                  case w ~ Some(p) => new AtomicWidget(w._1,w._2,w._3,Map(p:_*))})
  256.   }
  257.  
  258.  
  259.   def parseItem(str:String) = parse(Program, str)
  260.  
  261.   def main(args:Array[String]) {
  262.     var s = new java.util.Scanner(System.in)
  263.     while (true) {
  264.       val line = s.nextLine();
  265.       if (line.equals("quit")) return
  266.       parseItem(line) match {
  267.         case Success(result, _) => println(result.toString);
  268.         case _ => println("Could not parse the input string.")
  269.  
  270.       }
  271.     }
  272.   }
  273. }
Advertisement
Add Comment
Please, Sign In to add comment