[#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:[asbeta@home bug2]$ scalac Test.scala ParserBase.scala MathExp.scala [asbeta@home bug2]$ java -cp /opt/scala-2.3.3/share/scala/lib/scala-library.jar:. Test -7+-5+1-6+2+3 parsed: List(Symbol(-),Number(7),Symbol(+),Symbol(-),Number(5),Symbol(+),Number(1),Symbol(-),Number(6),Symbol(+)\ ,Number(2),Symbol(+),Number(3)) Exception in thread "main" java.lang.NullPointerException at MathExp$Parsers$class.$init$(MathExp.scala:16) at Test$$anon$1.<init>(Test.scala:11) at Test$.main(Test.scala:11) at Test.main(Test.scala) [asbeta@home bug2]$ scalac Test.scala ParserBase.scala MathExp2.scala [asbeta@home bug2]$ java -cp /opt/scala-2.3.3/share/scala/lib/scala-library.jar:. Test -7+-5+1-6+2+3 parsed: List(Symbol(-),Number(7),Symbol(+),Symbol(-),Number(5),Symbol(+),Number(1),Symbol(-),Number(6),Symbol(+)\ ,Number(2),Symbol(+),Number(3)) => parsed: Add(Neg(Const(7)),Add(Neg(Const(5)),Sub(Const(1),Add(Const(6),Add(Const(2),Const(3)))))) |
|||
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. |