I'm making a free time project with scala parsing combinators, following this guide, added to project with sbt with:
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.0.0"
I have a Lexer that compile, but the parser give me this error: method ~ in class Parser has changed semantics in version SpecificScalaVersion(2,9,0,Final): The call-by-name argument is evaluated at most once per constructed Parser object, instead of on every need that arises during parsing. on this line of code:
import scala.util.parsing.input.Positional
sealed trait AbstractSyntaxTree extends Positional
sealed trait Instruction extends AbstractSyntaxTree
final case class Label(text: String) extends Instruction
package svm.parser
import scala.util.parsing.combinator.Parsers
import scala.util.parsing.input.{NoPosition, Position, Reader}
import svm.{ParserError, Location}
import svm.lexer._
object SVMParser extends Parsers {
def label: Parser[Label] = positioned {
identifier ~ COL() ^^ { case IDENTIFIER(s) ~ _ => Label(s) }
}
}
This is the output of sbt compile:
[error] -- [E114] Syntax Error: /home/ap/Documents/scala/simple-stack-virtual-machine/src/main/scala/svm/parser/SVMParser.scala:59:15
[error] 59 | identifier ~ COL() ^^ { case IDENTIFIER(s) ~ _ => Label(s) }
[error] | ^^^^^^^^^^^^
[error] | |method ~ in class Parser has changed semantics in version SpecificScalaVersion(2,9,0,Final): The call-by-name argument is evaluated at most once per constructed Parser object, instead of on every need that arises during parsing.
[error] Explanation
[error] ===========
[error] The |method ~ in class Parser is marked with #migration indicating it has changed semantics
[error] between versions and the -Xmigration settings is used to warn about constructs
[error] whose behavior may have changed since version change.
I'm using wrong the ~ operator?
Related
I'd like to iterate over all the lines of a file in Scala but using the newline separator \n%\n instead of just \n. I'd like to be able to do this using the scala.io.Source abstract class.
Here's what I have so far:
object Main extends App {
val lines = Source.fromFile("quotes.txt").getLines
for {
line <- lines
} println(line)
}
This works fine using \n as a newline separator.
It seems that to be able to change the separator, I have to subclass scala.io.Source.LineIterator and implement my own isNewLine method.
However, when I try to subclass LineIterator like this:
import scala.io.Source
import scala.io.Source.LineIterator
class MyLineIterator extends LineIterator {
override def isNewLine(c: Char) = c == "\n%\n"
}
I get the following error when trying to build with sbt:
[info] Compiling 1 Scala source to /.../target/scala-2.12/classes...
[error] /.../Main.scala:6: value LineIterator is not a member of object scala.io.Source
[error] import scala.io.Source.LineIterator
[error] ^
[error] /.../Main.scala:8: not found: type LineIterator
[error] class MyLineiterator extends LineIterator {
[error] ^
[error] two errors found
Could somebody tell me why I can't import LineIterator and also provide a code snippet that allows me to specify a custom delimiter when iterating over the lines of a file?
Thanks for any help in advance.
Scala version 2.11.8
I have parent class
abstract class FR(externalId:String, code:String, message:String) extends Serializable {
val this.externalId=externalId;
val this.code = code;
val this.message = message;
def toString:String={
return "FRworks";
}
}
The child class is:
class RD extends FR {
def this(lpTransaction:LPTransaction)={
externalId =lpTransaction.getField("somethinghere").toString
...
}
}
The error is:
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
[info] Loading project definition from F:\workspace\frankcheckAPI\project
[info] Set current project to frankcheckapi (in build file:/F:/workspace/frankcheckAPI/)
[info] Compiling 20 Scala sources to F:\workspace\frankcheckAPI\target\scala-2.11\classes...
[error] F:\workspace\frankcheckAPI\src\main\scala\com\cardaccess\fraudcheck\RD.scala:9: 'this' expected but identifier found.
[error] externalId =lpTransaction.getField("somethinghere").toString
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
when I add this in front of externalId the error still:
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
[info] Loading project definition from F:\workspace\frankcheckAPI\project
[info] Set current project to frankcheckapi (in build file:/F:/workspace/frankcheckAPI/)
[info] Compiling 20 Scala sources to F:\workspace\frankcheckAPI\target\scala-2.11\classes...
[error] F:\workspace\frankcheckAPI\src\main\scala\com\cardaccess\fraudcheck\ReDFraudCheckResponse.scala:9: '}' expected but '.' found.
[error] this.externalId =lpTransaction.getField("somethinghere").toString
[error] ^
[error] F:\workspace\frankcheckAPI\src\main\scala\com\cardaccess\fraudcheck\ReDFraudCheckResponse.scala:12: eof expected but '}' found.
[error] }
[error] ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
Your code is very Java-influenced. There are couple of things wrong here; when you fix the obvious ones like missing class parameters in RD it boils down to not being able to reassign to val.
Let me give you an improved, Scala-fied version of the whole code.
abstract class FR(val externalId: String, val code: String, val message: String) extends Serializable
// dummy class
class LPTransaction {
def getField(s: String) = s
}
class RD(externalId: String, code: String, message: String) extends FR(externalId, code, message) {
def this(lpTransaction: LPTransaction) = {
this(lpTransaction.getField("somethinghere").toString, "defaultCode", "defaultMessage")
}
println(externalId)
}
val a = new RD(new LPTransaction) // prints "somethinghere"
Main improvements are:
You don't need private fields to be populated using arguments in the constructor. Scala favors immutability. Make your class arguments "vals", this means they will be available as public fields (instead of getters you will access them directly; this is contrary to OOP's encapsulation principle, but here it's ok because nobody can mess with them anyway since they are immutable; they may only be fetched)
Your subclass RD should be taking same fields as parameters as its parent class. Of course, you can then define an auxiliary constructor that takes only LPTransaction, but then you need to feed the parent class with some default values for the other parameters.
The rest kind of follows from this. I added the dummy implementation of LPTransaction to be able to compile. I also threw in a println statement in RD class just for the sake of example. Feel free to ask if something's not clear.
//scala automatically generates getters for passed in params. No need to set them explicitly. For immutable params use val, for mutable use var
abstract class FR(var externalId:String, val code:String, val message:String) extends Serializable {
//need to use override annotation for superclass methods
override def toString:String={
return "FRworks";
}
}
// notice how constructor parameters are passed to the base class when defining the child class.
class RD extends FR("someID","code","msg") {
def printId() = println(externalId)
}
val x = new RD
x.externalId = "new ID" //works because externalId is var (mutable)
x.code = "new code" //error because code is val (immutable)
x.printId //correctly prints the external id: someID
Here is the code I am trying to run:
import org.specs2.mock.Mockito
import org.specs2.mutable.Specification
import org.specs2.specification.Scope
import akka.event.LoggingAdapter
class MySpec extends Specification with Mockito {
"Something" should {
"do something" in new Scope {
val logger = mock[LoggingAdapter]
val myVar = new MyClassTakingLogger(logger)
myVar.doSth()
there was no(logger).error(any[Exception], "my err msg")
}
}
}
When running this, I get the following error:
[error] org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
[error] Invalid use of argument matchers!
[error] 2 matchers expected, 1 recorded:
[error] -> at org.specs2.mock.mockito.MockitoMatchers$class.any(MockitoMatchers.scala:47)
[error]
[error] This exception may occur if matchers are combined with raw values:
[error] //incorrect:
[error] someMethod(anyObject(), "raw String");
[error] When using matchers, all arguments have to be provided by matchers.
[error] For example:
[error] //correct:
[error] someMethod(anyObject(), eq("String by matcher"));
Which would make a lot of sense, but neither eq("my err msg") nor equals("my err msg") does the job as I get an error. What am I missing?
When you are using matchers to match parameters you have to use them for all parameters. as the all arguments have to be provided by matchers indicates.
Moreover if you use a specs2 matcher it needs to be strongly-typed. equals is a Matcher[Any] but there is no conversion from Matcher[Any] to a String which is what method accepts.
So you need a Matcher[T] or a Matcher[String] in your case. If you just want to test for equality, the strongly-typed matcher is ===
there was no(logger).error(any[Exception], ===("hey"))
I would like to add that you should be wary of default arguments, i.e. if using matchers when stubbing methods, make sure to pass argument matchers for all arguments, because default arguments will almost certainly have constant values - causing this same error to appear.
E.g. to stub the method
def myMethod(arg1: String, arg2: String arg3: String = "default"): String
you cannot simply do
def myMethod(anyString, anyString) returns "some value"
but you also need to pass an argument matcher for the default value, like so:
def myMethod(anyString, anyString, anyString) returns "some value"
Just lost half an hour figuring this out :)
SLF4J's varargs on the logging calls are quite useful in my Java work
Logger log = LoggerFactory.getLogger( getClass() );
log.debug( "Hello, {}. The current time is {}", "robert", new Date() );
Attempting to do this simple example in Play 2.1 Framework/Scala and I run into the compiler rejecting me.
import play.api._
import play.api.mvc._
import org.slf4j.LoggerFactory
object Application extends Controller {
val log: org.slf4j.Logger = LoggerFactory.getLogger(getClass())
def hb = Action {
val message = makeMessage()
// COMPILER HATES THIS: ambiguous reference compiler error here
log.info("Hello {}. The current time is {}", "robert", new java.util.Date() )
Ok(message)
}
def makeMessage(): String = { return "stuff" }
}
[dm2-server] $ compile
[info] Compiling 2 Scala sources to /Users/bobk/work/dm2-server/target/scala-2.10/classes...
[error] /Users/bobk/work/dm2-server/app/controllers/Application.scala:16: ambiguous reference to overloaded definition,
[error] both method info in trait Logger of type (x$1: String, x$2: <repeated...>[Object])Unit
[error] and method info in trait Logger of type (x$1: String, x$2: Any, x$3: Any)Unit
[error] match argument types (String,String,java.util.Date)
[error] log.info("Hello {}. The current time is {}", "robert", new java.util.Date() )
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
[error] Total time: 1 s, completed Jun 6, 2013 10:54:41 AM
What is that error and how do I overcome it to call through to the SLF4J API? If I can't do that, how can I use the Play 2.1 Logging Framework to get varargs on my logging calls? Something is not right in Scala-land.
What version of SLF4J are you using? If you can go back to 1.6.6 or later, you can avoid this issue in ambiguity. Those two signatures unfortunately look the exact same to scala and the compiler can't seem to differentiate which one you mean. The common suggestion is to roll back to a version of SLF4J (if even possible for you) where this overloaded method ambiguity will not exist. More info can be found at the links below:
https://groups.google.com/forum/?fromgroups#!topic/scala-language/ms4IVIu-xGw
https://github.com/typesafehub/scalalogging/issues/16
The "quick fix" for this is as follows:
Just force the last argument to be type Any and that resolves the compiler's issue(s) (and makes for slightly less code...)
logger.debug("hello {} / {} ", "Hello", "World":Any)
Or in your case:
log.info("Hello {}. The current time is {}", "robert", new java.util.Date():Any)
The following macro, extracted from a larger example, is supposed to create a tree with nothing but a reference to this:
def echoThisImpl(c:Context): c.Expr[Any] = {
import c.universe._
val selfTree = This(c.enclosingClass.symbol)
c.Expr[AnyRef](selfTree)
}
def echoThis: Any = macro CallMacro.echoThisImpl
But a call to echoThis such as
object Testing extends App {
val thisValue = CallMacro.echoThis
println(thisValue)
}
fails to compile, with the message
[error] /home/rafael/dev/scala/goose/goose-macros/src/test/scala/Testing.scala:8: type mismatch;
[error] found : <noprefix>
[error] required: Any
[error] val thisValue = CallMacro.echoThis
If I set the -Ymacro-debug-lite flag the generated tree is This(newTermName("<local Testing>")).
There are two options of achieving what you want:
1) Use This(tpnme.EMPTY). Currently this doesn't compile, so you'll have to use This(newTypeName("")) instead, but in RC1 this will be fixed.
2) Use This(c.enclosingClass.symbol.asModule.moduleClass). Currently this doesn't work, because of https://issues.scala-lang.org/browse/SI-6394, but in RC1 this will be fixed.