| [#928] | project: compiler | priority: low | category: missing feature | |
|---|---|---|---|---|
| submitter | assigned to | status | date submitted | |
| Burak | _ | _ | 2007-01-31 17:19:36.0 | |
| subject | [contrib #304] replacement of def into val breaks code | |||
| code |
====== Test.scala ======
import scala.util.parsing._
object Test {
def main(args: Array[String]) {
val args = "-7+-5+1-6+2+3"
System.out.println(args)
val ps = new ParseString(args) with ListParsers
ps.expr(ps.input) match {
case Some({list, _}) => {
System.out.println("parsed: " + list)
val ps2 = new ParseTokenSeq(list: Seq[Token]) with MathExp.Parsers
ps2.expr(ps2.input) match {
case Some({exp, _}) => System.out.println("=> parsed: " + exp)
case None => System.out.println("=> nothing parsed")
}
}
case None => System.out.println("nothing parsed")
}
}
}
====== ParserBase.scala ======
import scala.util.parsing._
trait CharParsers extends Parsers {
val any: Parser[char]
def chr(ch: char): Parser[char] =
for (val c <- any; c == ch) yield c
def chrSuchThat(p: char => boolean): Parser[char] =
for (val c <- any; p(c)) yield c
}
sealed abstract class Token
case class Symbol(sym: char) extends Token
case class Number(num: int) extends Token
trait TokenParsers extends Parsers {
val any: Parser[Token]
def symbol(sym: char): Parser[Symbol] =
for (val t <- any; t.isInstanceOf[Symbol];
t.asInstanceOf[Symbol].sym == sym)
yield t.asInstanceOf[Symbol]
val number: Parser[Number] =
for (val t <- any; t.isInstanceOf[Number])
yield t.asInstanceOf[Number]
}
trait ListParsers extends CharParsers {
val space: Parser[unit] =
for {
val _ <- rep(chrSuchThat(Character.isWhitespace))
} yield ()
val number: Parser[Token] =
for {
val d <- chrSuchThat(Character.isDigit)
val ds <- rep(chrSuchThat(Character.isDigit))
} yield Number(((d - '0') /: ds) ((x, digit) => x * 10 + digit - '0'))
val symbol: Parser[Token] =
for {
val sym <- any
} yield Symbol(sym)
val expr: Parser[List[Token]] =
for {
val _ <- space
val res <- number ||| symbol
val rest <- expr ||| succeed(List())
} yield res :: rest
}
class ParseString(s: String) extends Parsers {
type inputType = int
val input = 0
val any = new Parser[char] {
def apply(in: inputType): Parser[char]#Result =
if (in < s.length()) Some({s charAt in, in+1}) else None
}
}
class ParseTokenSeq(l: Seq[Token]) extends Parsers {
type inputType = int
val input = 0
val any = new Parser[Token] {
def apply(in: inputType): Parser[Token]#Result =
if (in < l.length) Some({l(in), in+1}) else None
}
}
====== MathExp.scala ======
import scala.util.parsing._
object MathExp {
sealed abstract class t
case class Const(num: int) extends t
case class Add(exp1: t, exp2: t) extends t
case class Sub(exp1: t, exp2: t) extends t
case class Neg(exp: t) extends t
trait Parsers extends TokenParsers {
// --- level 1 ----------------------------------------
val add: Parser[t] =
for {
val exp1 <- lvl2
val _ <- symbol('+')
val exp2 <- lvl1 ||| lvl2
} yield Add(exp1, exp2)
val sub: Parser[t] =
for {
val exp1 <- lvl2
val _ <- symbol('-')
val exp2 <- lvl1 ||| lvl2
} yield Sub(exp1, exp2)
val lvl1: Parser[t] =
add ||| sub
// --- level 2 ----------------------------------------
val const: Parser[t] =
for {
val num <- number
} yield Const(num.num)
val brackets: Parser[t] =
for {
val _ <- symbol('(')
val exp <- expr
val _ <- symbol(')')
} yield exp
val neg: Parser[t] =
for {
val _ <- symbol('-')
val exp <- lvl2
} yield Neg(exp)
val lvl2: Parser[t] =
const ||| brackets ||| neg
// --- dispatch ---------------------------------------
val expr: Parser[t] =
lvl1 ||| lvl2
}
}
====== MathExp2.scala ======
import scala.util.parsing._
object MathExp {
sealed abstract class t
case class Const(num: int) extends t
case class Add(exp1: t, exp2: t) extends t
case class Sub(exp1: t, exp2: t) extends t
case class Neg(exp: t) extends t
trait Parsers extends TokenParsers {
// --- level 1 ----------------------------------------
def add: Parser[t] =
for {
val exp1 <- lvl2
val _ <- symbol('+')
val exp2 <- lvl1 ||| lvl2
} yield Add(exp1, exp2)
def sub: Parser[t] =
for {
val exp1 <- lvl2
val _ <- symbol('-')
val exp2 <- lvl1 ||| lvl2
} yield Sub(exp1, exp2)
def lvl1: Parser[t] =
add ||| sub
// --- level 2 ----------------------------------------
def const: Parser[t] =
for {
val num <- number
} yield Const(num.num)
def brackets: Parser[t] =
for {
val _ <- symbol('(')
val exp <- expr
val _ <- symbol(')')
} yield exp
def neg: Parser[t] =
for {
val _ <- symbol('-')
val exp <- lvl2
} yield Neg(exp)
def lvl2: Parser[t] =
const ||| brackets ||| neg
// --- dispatch ---------------------------------------
def expr: Parser[t] =
lvl1 ||| lvl2
}
}
===
P.S. Rather long code, sorry about that. |
|||
| what happened | The difference between MathExp.scala & MathExp2.scala is that all redundant defs was replaced with vals (in \
MathExp.scala).
Following shell session should explain:
|
|||
| what expected | Equivalence of output from MathExp.scala & MathExp2.scala. | |||
| [back to overview] | ||||
| Burak edited on 2007-01-31 17:20:36.0 |
| this is a feature request in disguise: since val's are not lazily initialized, the above fails with nullpointer exceptions. I noticed the same in compiler construction exercises, just added here so doesn't get lost. |