Reputation:
I'm using Scala parser combinators to write parsers for a DSL for a constraint programming language that I'm working on. One of the things I'd like to be able to parse are expressions of the form:
<resource1> <relationship_name> <resource2>
For example:
Teacher canTeach Class
I'm trying to match this using:
stringLiteral ~ stringLiteral ~ stringLiteral
But what I really want is to be able to match it by looking up if the first and last strings are defined resources and if the middle one is actually a relationship that is in scope.
How can I define a function that allows me to put these conditions on matching and then use it.
Upvotes: 2
Views: 136
Reputation: 22374
There is a difference between grammar and syntax. stringLiteral ~ stringLiteral ~ stringLiteral
has no restrictions on what stringLiteral
is - even if you add some restriction (like stringLiteral ~ "canTeach" | "canWhatever" ~ stringLiteral
)" - it should be known before parser is constructed (not during parsing itself). However, your desirable restriction is seems to be semantical which means that some grammatically correct sentences like "Teacher canTeach Microwave" may not be semantically correct - so this check should be done after parsing. You have AST as parser's output - so you could just validate this AST, something like:
case class Knowledge(subject: String, can: Boolean, predicate: String, obj: String)
val knowledges = parse("Teacher can teach Class", "Teacher cannot teach Class")
knowledges.groupBy(x => (x.subject, x.predicate, x.obj)).mapValues(v => if(v.forall(v.head.can == _.can)) Right(v) else Left(v)))
Upvotes: 2