Is there a way to pass contextual information to parsers?

Viewed 343

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).

2 Answers
Related