I am parsing a small declarative language where in a scope you can have variables declared (with a type), and then later on, just like in most other languages, the name (without the type) is used.
The declaration of variable would look like this:
?varname
?varname1 ?varname2 - type1
?varname3 ?varname4 ?varname5 - type2
If the type is omitted, the default type should be object
, like in the first case.
So for that I have a specific parser which returns a list of my own domain object called LiftedTerm
(you can just assume its a tuple with the name of the variable and the type of the variable, in reality there is some more stuff in it but irrelevant for this problem):
def typed_list_variables : Parser[List[LiftedTerm]]= typed_variables.+ ^^ { case list => list.flatten.map(variable =>
LiftedTerm(variable._1, variable._2 match {
case "object" => ObjectType
case _ => TermType(variable._2)
})) }
def typed_variables = ((variable+) ~ (("-" ~> primitive_type)?)) ^^ {
case variables ~ primitive_type =>
for (variable <- variables) yield variable -> primitive_type.getOrElse("object")
}
def variable = """\?[a-zA-Z][a-zA-Z0-9_-]*""".r
def primitive_type = """[a-zA-Z][a-zA-Z0-9_-]*""".r
All this works perfectly fine.
Now further down in the same 'scope' I have to parse the parts where there is a reference to these variables. The variable obviously won't be declared again in full. So, in the above example, places where ?varname1
is used won't include type1
. However, when I parse the rest of the input I wish to get the reference of the right LiftedTerm
object, rather than just a string.
I have some recursive structures in place, so I don't wish to do this mapping at the top level parser. I don't wish to make a 'global mapping' of these either in my RegexParsers
object because most of these are scoped and only relevant for a small piece of the input.
Is there a way of passing contextual information to a parser? Ideally I pass the list of LiftedTerm
(or better still a map from the variable names String -> LiftedTerm
) into the recursive parser calls.
(Apologies if this is something obvious, I am still new to Scala and even newer to parser combinators).
scala.util.parsing.ast.Binders
would have let you do something along these lines, but it has been deprecated for a while now and is on its way to extinction. – Robustious