Play for Scala and Anorm: cannot create a simple parser - scala

There should be something simple here, though I'm completely missing it, since I'm noob in Scala and Play. Here's the code:
case class ExceptionInfo(ExceptionType: String, Message: String, StackTrace: Seq[String])
object ExceptionInfo
{
val excInfoParser = {
get[String]("ExceptionInfo.ExceptionType") ~
get[String]("Message") ~
get[String]("ExceptionInfo.StackTrace") map {
case ExceptionType ~ Message ~ StackTrace => ExceptionInfo(ExceptionType, Message, StackTrace.split("\r\n"))
}
}
}
This doesn't compile, with following output:
Description Resource Path Location Type
not found: value ExceptionType Application.scala /testme/app/controllers line 40 Scala Problem
not found: value Message Application.scala /testme/app/controllers line 40 Scala Problem
not found: value StackTrace Application.scala /testme/app/controllers line 40 Scala Problem
not found: value ExceptionType Application.scala /testme/app/controllers line 40 Scala Problem
Thanks in advance!

Should work when you name the variables in lowercase:
case exceptionType ~ message ~ stackTrace => ExceptionInfo(exceptionType, message, stackTrace.split("\r\n"))
The lowercase is what distinguishes variables to be bound to (what you're looking for) from constants to be matched against. See here and here for more.

Related

Using `err` in a Child Parser

In the following Parser:
object Foo extends JavaTokenParsers {
def word(x: String) = s"\\b$x\\b".r
lazy val expr = aSentence | something
lazy val aSentence = noun ~ verb ~ obj
lazy val noun = word("noun")
lazy val verb = word("verb") | err("not a verb!")
lazy val obj = word("object")
lazy val something = word("FOO")
}
It will parse noun verb object.
scala> Foo.parseAll(Foo.expr, "noun verb object")
res1: Foo.ParseResult[java.io.Serializable] = [1.17] parsed: ((noun~verb)~object)
But, when entering a valid noun, but an invalid verb, why won't the err("not a verb!") return an Error with that particular error message?
scala> Foo.parseAll(Foo.expr, "noun vedsfasdf")
res2: Foo.ParseResult[java.io.Serializable] =
[1.6] failure: string matching regex `\bverb\b' expected but `v' found
noun vedsfasdf
^
credit: Thanks to Travis Brown for explaining the need for the word function here.
This question seems similar, but I'm not sure how to handle err with the ~ function.
Here's another question you might ask: why isn't it complaining that it expected the word "FOO" but got "noun"? After all, if it fails to parse aSentence, it's then going to try something.
The culprit should be obvious when you think about it: what in that source code is taking two Failure results and choosing one? | (aka append).
This method on Parser will feed the input to both parsers, and then call append on ParseResult. That method is abstract at that level, and defined on Success, Failure and Error in different ways.
On both Success and Error, it always take this (that is, the parser on the left). On Failure, though, it does something else:
case class Failure(override val msg: String, override val next: Input) extends NoSuccess(msg, next) {
/** The toString method of a Failure yields an error message. */
override def toString = "["+next.pos+"] failure: "+msg+"\n\n"+next.pos.longString
def append[U >: Nothing](a: => ParseResult[U]): ParseResult[U] = { val alt = a; alt match {
case Success(_, _) => alt
case ns: NoSuccess => if (alt.next.pos < next.pos) this else alt
}}
}
Or, in other words, if both sides have failed, then it will take the side that read the most of the input (which is why it won't complain about a missing FOO), but if both have read the same amount, it will give precedence to the second failure.
I do wonder if it shouldn't check whether the right side is an Error, and, if so, return that. After all, if the left side is an Error, it always return that. This look suspicious to me, but maybe it's supposed to be that way. But I digress.
Back to the problem, it would seem that it should have gone with err, as they both consumed the same amount of input, right? Well... Here's the thing: regex parsers skip whiteSpace first, but that's for regex literals and literal strings. It does not apply over all other methods, including err.
That means that err's input is at the whitespace, while the word's input is at the word, and, therefore, further on the input. Try this:
lazy val verb = word("verb") | " *".r ~ err("not a verb!")
Arguably, err ought to be overridden by RegexParsers to do the right thing (tm). Since Scala Parser Combinators is now a separate project, I suggest you open an issue and follow it up with a Pull Request implementing the change. It will have the impact of changing error messages for some parser (well, that's the whole purpose of changing it :).

Type mismatch in scala quasiquote of macro definition: "type mismatch; found : field.NameType required: c.universe.TermName"

I asked a longer question, but it seems it's too much code for people to sort through so I've created this question to focus on one smaller, specific problem I'm facing regarding use of macros in Scala.
Consider the following code snippet:
val tpe = weakTypeOf[T]
val companion = tpe.typeSymbol.companionSymbol
val fields = tpe.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}.get.paramss.head
val toMapParams = fields.map { field =>
val name = field.name
val decoded = name.decoded
q"$decoded -> t.$name"
}
Note that fields is just the list of parameters for the primary constructor of a case class in this code. Where I'm confused is the result of the quasiquote q"$decoded -> t.$name". What does this mean exactly? And what type should it have? I'm getting a compile error stating the following:
Multiple markers at this line
- Implicit conversions found: q"$decoded -> t.$name" => Quasiquote(q"$decoded -> t.
$name")
- type mismatch; found : field.NameType required: c.universe.TermName
- type mismatch; found : field.NameType required: c.universe.TermName
Can anyone explain this error? Thanks.
The type of fields is List[Symbol], which means that the type of names of those fields is inconclusive (unknown whether it's a TermName or TypeName). This means that you can't insert such names essentially anywhere in a quasiquote.
A simple fix would be to do val name = field.name.toTermName, explicitly telling the compiler that it's looking at a term name, so that quasiquote knows how to process it.

How to get meaningful message for failing Specs2 test on all elements of a collection?

I have a list of files exampleProblems, to each of which I want to apply a method and check that it doesn't throw an exception. The problem is that I don't get a good failure message from Specs2. I need to find out which element caused the problem. I already tried adding an aka, but with no success.
Here is the code:
def is: Fragments =
"parse all example uai files" ! (exampleProblems must contain((p: String) => {
Problem.parseUAIProblem(ClassLoader.getSystemResourceAsStream(p)).aka(p) must throwAn[Exception].not
}).forall)
And here is the message I'm getting:
java.lang.Exception: There is 1 failure Got the exception
java.lang.IllegalArgumentException: requirement failed: variables are
not ordered increasingly
at
vultura.fastfactors.UAIParserTest$$anonfun$is$1$$anonfun$apply$1.apply(UAIParserTest.scala:24)
at
vultura.fastfactors.UAIParserTest$$anonfun$is$1$$anonfun$apply$1.apply(UAIParserTest.scala:24)
This means that the throwA[E] matcher should be improved to display the expectable description when using aka. I'll fix this but as a work-around you can write:
class TestSpec extends Specification { def is =
"parse all example uai files" ! {
Seq("a", "b") must contain { (p: String) =>
s"$p is ok" ==> { { sys.error("bang"); p} must not (throwAn[Exception]) }
}.forall
}
}
This displays:
[info] x parse all example uai files
[error] There is 1 failure
[error] a is not ok because Got the exception java.lang.RuntimeException: bang

Enumeration and mapping with Scala 2.10

I'm trying to port my application to Scala 2.10.0-M2. I'm seeing some nice improvements with better warnings from compiler. But I also got bunch of errors, all related to me mapping from Enumeration.values.
I'll give you a simple example. I'd like to have an enumeration and then pre-create bunch of objects and build a map that uses enumeration values as keys and then some matching objects as values. For example:
object Phrase extends Enumeration {
type Phrase = Value
val PHRASE1 = Value("My phrase 1")
val PHRASE2 = Value("My phrase 2")
}
class Entity(text:String)
object Test {
val myMapWithPhrases = Phrase.values.map(p => (p -> new Entity(p.toString))).toMap
}
Now this used to work just fine on Scala 2.8 and 2.9. But 2.10.0-M2 gives me following warning:
[ERROR] common/Test.scala:21: error: diverging implicit expansion for type scala.collection.generic.CanBuildFrom[common.Phrase.ValueSet,(common.Phrase.Value, common.Entity),That]
[INFO] starting with method newCanBuildFrom in object SortedSet
[INFO] val myMapWithPhrases = Phrase.values.map(p => (p -> new Entity(p.toString))).toMap
^
What's causing this and how do you fix it?
It's basically a type mismatch error. You can work around it by first converting is to a list:
scala> Phrase.values.toList.map(p => (p, new Entity(p.toString))).toMap
res15: scala.collection.immutable.Map[Phrase.Value,Entity] = Map(My phrase 1 -> Entity#d0e999, My phrase 2 -> Entity#1987acd)
For more information, see the answers to What's a “diverging implicit expansion” scalac message mean? and What is a diverging implicit expansion error?
As you can see from your error, the ValueSet that holds the enums became a SortedSet at some point. It wants to produce a SortedSet on map, but can't sort on your Entity.
Something like this works with case class Entity:
implicit object orderingOfEntity extends Ordering[Entity] {
def compare(e1: Entity, e2: Entity) = e1.text compare e2.text
}

Scala-IDE or Scala unjustified syntax ambiguity

I am learning Scala with Scala-IDE in Eclipse. While following the Chapter 9: Control Abstraction, part 1: Reducing Code Duplication in the Programming in Scala book, I have written the code from the book (fully represented below), it worked fine! When I started removing the unnecessary blank lines, a strange thing happened. Here is the entire code before the removal of the blank lines in the filterFiles() method:
object Code_c09s01_ControlAbstraction extends App{
object FilesFilter {
private def filterFiles(path: String, pattern: String, matcher: (String, String) => Boolean) = {
val files = (new java.io.File(path)) listFiles
for(file <- files if matcher(file.getName, pattern)) yield file
}
def filterExtension(path: String, pattern: String) = filterFiles(path, pattern, _.endsWith(_))
def filterName(path: String, pattern: String) = filterFiles(path, pattern, _.contains(_))
def filterRegex(path: String, pattern: String) = filterFiles(path, pattern, _.matches(_))
}
def printArray[A](message: String, arr: Array[A]) {
println (message)
println (arr mkString("\n"))
}
def test() {
val path = "C:\\";
printArray("--- filtering by ext: ---", FilesFilter.filterExtension(path, ".txt"))
printArray("--- filtering by containment: ---", FilesFilter.filterName(path, "1"))
printArray("--- filtering by regex: ---", FilesFilter.filterRegex(path, "."))
}
test
}
which works just fine! However, after removing the blank lines from the filterFiles() method, the method now looks like this:
private def filterFiles(path: String, pattern: String, matcher: (String, String) => Boolean) = {
val files = (new java.io.File(path)) listFiles
for(file <- files if matcher(file.getName, pattern)) yield file
}
And the IDE gives me errors on both lines of the body. The error of the first line says:
ambiguous reference to overloaded definition, both method listFiles in class File of type (x$1: java.io.FileFilter)Array[java.io.File] and method listFiles in class File of type
(x$1: java.io.FilenameFilter)Array[java.io.File] match argument types (Null)
the error on the second line says:
illegal start of simple expression
and all the three calls to the printArray() in the test() method now also tell this:
type mismatch; found : Unit required: Array[?]
What does it all mean? Scala is not supposed to behave like Python when code alignment can ruin the code flow... so how come that removing the blank line between the first and the second line of the body of the filterFiles() method puts up such a serious error? Is it a bug somewhere or does it follow directly from the rules of Scala? Note: if I add ; between the line, it sorts everything out. Is it just semicolon inference bug?
When object's method can none or single argument you can call it like
val files = object method arg
or, in your snippet
val files = object method
arg
In your code compiler wants to call listfiles with an for expression as an agument which returns Array[File]. And complains that listFiles hasn't implementation with this type of argument. Empty line prevents treating for expression as a parameter for listFiles function
Looks like semicolon inference problem as you suggest, I guess the compiler expects method arguments if you leave parenthesis out. Instead of semicolon, you can add parenthesis after listFiles:
val files = (new java.io.File(path)) listFiles ()