More arsing around with Scala

More arsing around with Scala. This time, trying to reimplement lesscss. This is about two hours worth of hacking:

object LessParser extends RegexParsers { def parse(spec: String) : Sequence = { parseAll(sequence, spec) match { case Success(l, _) => l case Failure(m, ) => throw new IllegalArgumentException(m) case Error(m, ) => throw new IllegalArgumentException(m) } } def sequence = rep(namedNested | atom) ^^ { Sequence() } def namedNested = nestedName~"{"~rep(atom)~"}" ^^ { case name~"{"~contents~"}" => NamedNested(name, contents) } def nestedName = """[.#][a-zA-Z]+""".r def atom = variableDef | variableUse | text def text = "[^@{}]+".r ^^ { Text() } def variableDef = "@"~variableName~":"~variableValue~";" ^^ { case "@"~name~":"~value~";" => VariableDef(name, value) } def variableUse = "@"~variableName ^^ { case "@"~name => VariableUse(name) } def variableName = "[a-z-]+".r def variableValue = "[^;]+".r }

abstract class Tree { def eval(defs: Map[String, String], out: StringBuffer) : Map[String, String] } case class Sequence(parts: List[Tree]) extends Tree { def eval(defs: Map[String, String], out: StringBuffer) : Map[String, String] = { parts.foldLeft (defs) { (accumDefs : Map[String, String], part : Tree) => part.eval(accumDefs, out) } } } case class NamedNested(name: String, contents: List[Atom]) extends Tree { def eval(defs: Map[String, String], out: StringBuffer) : Map[String, String] = { out.append(name) out.append(" {") contents.foldLeft (defs) { (accumDefs : Map[String, String], part : Tree) => part.eval(accumDefs, out) } out.append("}") defs } } abstract case class Atom() extends Tree case class VariableDef(name: String, value: String) extends Atom { def eval(defs: Map[String, String], out: StringBuffer) : Map[String, String] = { defs + (name -> value) } } case class VariableUse(name: String) extends Atom { def eval(defs: Map[String, String], out: StringBuffer) : Map[String, String] = { out.append(defs(name)) defs } } case class Text(value: String) extends Atom { def eval(defs: Map[String, String], out: StringBuffer) : Map[String, String] = { out.append(value) defs } }

object Less { def main(args : Array[String]) : Unit = { println(LessParser.parse("@nice-blue: #5B83AD;")) println(LessParser.parse("@nice-blue")) println(LessParser.parse("@nice-blue: #5B83AD; @nice-blue")) println(LessParser.parse("@nice-blue: #5B83AD; #header { background-color: @nice-blue; }"))

var fullExample = """ @nice-blue: #5B83AD; #header { background-color: @nice-blue; } """

var buf = new StringBuffer LessParser.parse(fullExample).eval(Map(), buf) println(buf) } }

Output:

Sequence(List(VariableDef(nice-blue,#5B83AD))) Sequence(List(VariableUse(nice-blue))) Sequence(List(VariableDef(nice-blue,#5B83AD), VariableUse(nice-blue))) Sequence(List(VariableDef(nice-blue,#5B83AD), NamedNested(#header,List(Text(background-color: ), VariableUse(nice-blue), Text(; ))))) #header {background-color: #5B83AD; }

It does variables and the beginnings of mixins. It's actually quite lame e.g. it throws away whitespace. Hohum, time to learn more about parsers in Scala...