0

I'm trying to modify an example from DSLs in Action.

Originally, this code was used to parse items followed by account.

  lazy val order: Parser[Order] = 
    items ~ account_spec ^^ {
      case i ~ a => Order(i, a)
    }

The following text could be parsed with the above parser:

(100 IBM shares to buy at max 45) for account "A1234
------------- item -------------  ------ account ----

But, I'd like to add FOO and an optional not values to the parser:

  lazy val order: Parser[Order] = 
    items <~ "FOO" ~> ("not"?) ~ account_spec ^^ {
      case i ~ n ~ a => println(n); Order(i, a)
    }

FOO must follow account and, optionally, not will follow.

Example:

(100 IBM shares to buy at max 45) FOO not for account "A1234
---------- item ------------------ --- --- ------ account ----

However, the above code gives me this compile-time error:

[WARNING] ....\OrderDsl.scala:19: error: constructor cannot be instantiated to 
expected type;
[WARNING]  found   : ch8.trading.semantic.dsl.OrderDsl.~[a,b]
[WARNING]  required: ch8.trading.semantic.dsl.AST.Items
[WARNING]       case i ~ n ~ a => println(n); Order(i, a)
[WARNING]                  ^

How can I modify the case statement to support parsing an optional "not" value?

1 Answer 1

3

a <~ "FOO" ~> b means "ignore results of parsers "FOO" and b and return the result of a".

Rewrite your method like this:

lazy val order: Parser[Order] = 
  items ~ opt("FOO") ~ opt("not") ~ account_spec ^^ {
    case i ~ _ ~ n ~ a => println(n); Order(i, a)
  }

General mnemonic for ~> and <~: you can ignore from start to operator or from operator to end, but not the middle part of expression.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, @senia. Your answer cleared up my mis-use of ~> and <~ together.
@KevinMeredith: Actually you could use items ~ (opt("FOO") ~> opt("not") ~ account_spec) ^^ { case i ~ (n ~ a) => ...}.
If we added case i ~ foo ~ n ..., is it true that foo could only equal None and Some("FOO")? My pattern match on foo match { case None => ... case Some("FOO") is telling me that the match is non-exhaustive.
@KevinMeredith: yes, but compiler knows only the type of foo. You should use foo.isDefined.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.