Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
- //import scala.util.parsing.combinator.syntactical._;
- import scala.util.matching.Regex
- import scala.util.parsing.combinator._;
- object TextStyle extends Enumeration {
- type TextStyle = Value;
- val bold, italic, regular = Value;
- }
- object HAlign extends Enumeration {
- type HAlign = Value;
- val left, center, right = Value;
- }
- object VAlign extends Enumeration {
- type VAlign = Value;
- val top, middle, bottom = Value;
- }
- object BinOp extends Enumeration {
- type BinOp = Value;
- val *, -, +, /, ||, && = Value;
- }
- object UnOp extends Enumeration {
- type UnOp = Value;
- val !, - = Value;
- }
- import TextStyle._, HAlign._, VAlign._, BinOp._, UnOp._
- class Color(hexa:String) {
- assume(hexa.length == 8 && hexa.startsWith("0x"), "Invalid Color Format " + hexa)
- val red = hexa.substring(2,4).toInt
- val green = hexa.substring(4,6).toInt
- val blue = hexa.substring(6,8).toInt
- }
- trait Dim
- case object AutoSize extends Dim
- /* TODO: currently we don't support conditional sizes and this *may* require
- * changes. Anyway, when traversing the AST simply make sure that the
- * Expr is a Dim */
- trait Expr
- trait DirectExpr extends Expr with Dim /* Anything but conditions */
- case class Literal(value:Any, init:Boolean) extends DirectExpr
- case class Var(id:String) extends DirectExpr
- case class PropVar(loc:String, id:String) extends DirectExpr
- case class BinaryOp(left:Expr, op:BinOp, right:Expr) extends DirectExpr
- case class UnaryOp(op:UnOp, e:Expr) extends DirectExpr
- case class Font(size:Int, face:String, style:TextStyle) extends DirectExpr
- case class Cond(conds:List[(Expr,Expr)], otherwise:Expr) extends Expr
- trait Widget {
- def kind(): String
- def properties(): Map[String,Expr]
- def width(): Dim
- def height(): Dim
- def hasChildren (): Boolean
- def getChildren (): Iterable[Widget]
- }
- abstract class WidgetImp(k:String, w:Dim,h:Dim,p:Map[String,Expr],hc:Boolean,gc:Iterable[Widget]) extends Widget {
- def kind = k
- def properties = p
- def width = w
- def height = h
- def hasChildren = hc
- def getChildren = gc
- }
- /* An atomic widget is either one of the built in widgets, or one which was defined
- * as a "subprogram" somewhere else
- * Note that for the empty widget, we will use the empty string as it's kind
- */
- class AtomicWidget(k:String, w:Dim,h:Dim,p:Map[String,Expr])
- extends WidgetImp(k,w,h,p,false,List())
- class HVContainer(ws:List[Widget], isVertical:Boolean)
- extends WidgetImp(if (isVertical) "---" else "|", AutoSize, AutoSize, Map(), true, ws)
- class OneContainer(ws:Widget, w:Dim, h:Dim, p:Map[String,Expr])
- extends WidgetImp("@", w, h, p, true, List(ws))
- object ConstMatcher {
- val IntPattern = "[0-9]+"
- val BooleanPattern = "(true)|(false)"
- /* A tricky one! This should look like
- * "(([^"]|(\\"))*)"
- * Which means
- * 1. start with a quote
- * 2. Repeat(non-quote OR (slash quote))
- * 3. End with a quote
- * Note that in order to specify the backslash, we need 2 backslashes!
- */
- val StringPattern = "\"(([^\"]|(\\\\\"))*)\""
- val ColorPattern = "0x[A-Fa-f0-9]{6}"
- val IdPattern = "[A-Za-z_][A-Za-z0-9_]*"
- val TextStylePattern = "(bold)|(italic)|(regular)"
- val HAlignPattern = "(top)|(middle)|(bottom)"
- val VAlignPattern = "(left)|(center)|(right)"
- val BinaryOpPattern = "(\\|\\|)|(&&)|[\\Q+-/*\\E]"
- val UnaryOpPattern = "!|-"
- def isInt (s:String) = s.matches(IntPattern)
- def isBoolean (s:String) = s.equals(BooleanPattern)
- def isString (s:String) = s.matches(StringPattern)
- def isColor (s:String) = s.matches(ColorPattern)
- def isId (s:String) = s.matches(IdPattern)
- def isTextStyle (s:String) = s.matches(TextStylePattern)
- def isHAlign (s:String) = s.matches(HAlignPattern)
- def isVAlign (s:String) = s.matches(VAlignPattern)
- def isBinaryOp (s:String) = s.matches(BinaryOpPattern)
- def isUnaryOp (s:String) = s.matches(UnaryOpPattern)
- 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)
- def CtoBinaryOp (s:String) = BinOp.withName(s)
- def CtoUnaryOp (s:String) = UnOp.withName(s)
- }
- import ConstMatcher._
- class ExprParser extends RegexParsers {
- def rr(pat:String) = regex(new Regex(pat))
- def pNumericConst = rr(IntPattern)
- def pStringConst = rr(StringPattern)
- def pColorConst = rr(ColorPattern)
- def pId = rr(IdPattern)// ^^ { id => new Var(id) }
- def pBooleanConst = rr(BooleanPattern)
- def pTextStyleConst = rr(TextStylePattern)
- def pHAlignConst = rr(HAlignPattern)
- def pVAlignConst = rr(VAlignPattern)
- def pExpr = pCondExpr | pDirectExpr | pInitLiteral | pFontExpr
- def pFontExpr = ("(" ~ pNumericConst ~ "," ~ pStringConst ~ "," ~ pTextStyleConst ~ ")") ^^ {case "(" ~ si ~ "," ~ fa ~ "," ~ st ~ ")" => new Font (CtoInt(si),CtoString(fa),CtoTextStyle(st)) }
- def pBinop = rr(BinaryOpPattern)
- def pUnop = rr(UnaryOpPattern)
- def pDirectExpr:Parser[DirectExpr] = (pLiteral
- | (pId ^^ { name => new Var(name) })
- | ((pDirectExpr ~ pBinop ~ pDirectExpr) ^^ { case l ~ op ~ r => new BinaryOp(l,CtoBinaryOp(op),r) })
- | ((pUnop ~ pDirectExpr) ^^ { case op ~ v => new UnaryOp(CtoUnaryOp(op),v) })
- | ("(" ~> pDirectExpr <~ ")")
- | ((pId ~ "." ~ pId) ^^ { case l ~ "." ~ p => new PropVar(l,p)}))
- def pInitLiteral = "?" ~> "(" ~> pLiteral <~ ")" ^^ { lt => new Literal(lt.value,true)}
- def pCond = (pDirectExpr ~ "=>" ~ pDirectExpr ~ ",") ^^ {case e1 ~ "=>" ~ e2 ~ "," => (e1,e2)}
- def pCondExpr = ("{" ~ (pCond *) ~ "otherwise" ~ pDirectExpr ~ "}") ^^ {case "{" ~ cnds ~ "otherwise" ~ o ~ "}" => new Cond(cnds,o)}
- def pLiteral = ((pNumericConst ^^ { numstr => new Literal(CtoInt(numstr), false) })
- | (pStringConst ^^ { sstr => new Literal(CtoString(sstr), false) })
- | (pBooleanConst ^^ { cb => new Literal(CtoBoolean(cb), false) })
- | (pColorConst ^^ { cstr => new Literal(CtoColor(cstr), false) })
- | (pHAlignConst ^^ { ha => new Literal(CtoHAlign(ha), false) })
- | (pVAlignConst ^^ { va => new Literal(CtoVAlign(va), false) })
- | (pTextStyleConst ^^ { ts => new Literal(CtoTextStyle(ts), false) }))
- }
- object GuiParserNew extends /* StandardTokenParsers */ ExprParser {
- /* TODO: correct me! */
- def expandMacro (w:Widget, index:String, start:Int, end:Int):List[Widget] = {
- var ws:Array[Widget] = new Array[Widget](end-start+1)
- for (i <- start to end) { /* Includes last index */
- ws(i-start) = w /* TODO - add macro defs and different index each time */
- }
- return ws.toList
- }
- /* A program is composed of many widgets definitions */
- def Program:Parser[List[(String,Widget)]] = (WidgetSpec /* | LinearProgramSpec */) *
- /* TODO!! */
- def LinearProgramSpec = "long ! and @ random # string $ that % should ^ never & appear"
- /* Each definition is made of a name and a widget */
- def WidgetSpec:Parser[(String,Widget)] = {
- (pId ~ "<-" ~ pWidget) ^^ { case id ~ "<-" ~ w => id -> w }
- }
- /* Each widget is either atomic, or vertical/horizontal composition of several
- * other widgets
- * FIXME - precedence
- */
- def pWidget:Parser[Widget] = {
- (pAtomicWidget
- | (rep1sep (pWidget, "|") ^^ { ls => new HVContainer (ls, false) })
- | (rep1sep (pWidget, "---") ^^ { ls => new HVContainer (ls, true) })
- | ((pWidget ~ "*|*" ~ pRangeSpec) ^^ { case w ~ "*|*" ~ rs => new HVContainer(expandMacro(w, rs._1, rs._2, rs._3), false)} )
- | ((pWidget ~ "*---*" ~ pRangeSpec) ^^ { case w ~ "*---*" ~ rs => new HVContainer(expandMacro(w, rs._1, rs._2, rs._3), true)} )
- | ((("(" ~> pWidget <~ ")") ~ (pWidgetSizeDef ?) ~ (pWidgetPropList ?)) ^^ {
- case w ~ None ~ None => w
- case w ~ Some(sd) ~ None => new OneContainer(w, sd._1, sd._2, Map())
- case w ~ None ~ Some(pl) => new OneContainer(w, AutoSize, AutoSize, Map(pl :_*))
- case w ~ Some(sd) ~ Some(pl) => new OneContainer(w, sd._1, sd._2, Map(pl :_*))
- }))
- }
- /* When duplication widgets by iteration, their iteration range will look like
- * this */
- def pRangeSpec:Parser[(String,Int,Int)] = {
- (pId ~ "=" ~ pNumericConst ~ ":" ~ pNumericConst) ^^ { case id ~ "=" ~ s ~ ":" ~ e => (id, s.toInt, e.toInt) }
- }
- // WidgetDim ::= "?" | NumericConst | "(" DirectExpr ")"
- def pWidgetDim:Parser[Dim] = {
- ((pNumericConst ^^ { num => new Literal(CtoInt(num), false) })
- | ("?" ^^ { d => AutoSize })
- | ("(" ~> pDirectExpr <~ ")"))
- }
- // WidgetSizeDef ::= ":" Dimnsion "x" Dimension
- def pWidgetSizeDef:Parser[(Dim,Dim)] = {
- ":" ~> ((pWidgetDim ~ "x" ~ pWidgetDim) ^^ { case w ~ "x" ~ h => (w,h) })
- }
- // WidgetType ::= Id | ""
- def pWidgetType = pId ||| ""
- // WidgetDef ::= "(" WidgetType WidgetSizeDef ? ")"
- def pAtomicWidgetDef:Parser[(String,Dim,Dim)] = {
- "(" ~> ((pWidgetType ~ ((":" ~> pWidgetSizeDef) ?)) ^^ { case t ~ Some(n) => (t,n._1,n._2)
- case t ~ None => (t,AutoSize,AutoSize)}) <~ ")"
- }
- // WidgetProp ::= Id "=" Expr
- def pWidgetProp:Parser[(String,Expr)] = (pId ~ "=" ~ pExpr) ^^ {case id ~ "=" ~ expr => (id,expr)}
- // WidgetPropList ::= "[" WidgetProp * "]"
- def pWidgetPropList:Parser[List[(String,Expr)]] = {
- "[" ~> (pWidgetProp *) <~ "]"
- }
- // AtomicWidget ::= AtomicWidgetDef pWidgetPropList ?
- def pAtomicWidget:Parser[AtomicWidget] = {
- (pAtomicWidgetDef ~ (pWidgetPropList ?) ^^ { case w ~ None => new AtomicWidget(w._1,w._2,w._3,Map())
- case w ~ Some(p) => new AtomicWidget(w._1,w._2,w._3,Map(p:_*))})
- }
- def parseItem(str:String) = parse(Program, str)
- def main(args:Array[String]) {
- var s = new java.util.Scanner(System.in)
- while (true) {
- val line = s.nextLine();
- if (line.equals("quit")) return
- parseItem(line) match {
- case Success(result, _) => println(result.toString);
- case _ => println("Could not parse the input string.")
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment