def LogicalAtom = FunctSymbol ~ "(" ~ PredicateInnerTerms ~ ")" ~ EOI ~> ( (x, y) => Atom(functor = x, terms = y.elems))
def PredicateInnerTerms = rule { oneOrMore(FunctionTerm | Var | Cons).separatedBy(",") ~> ( x => ExpressionList(x.toList) ) }
def FunctionTerm = rule { FunctSymbol ~ "(" ~ InnerTerms ~ ")" ~> ((x, y) => Atom(functor = x, terms = y.elems)) }
def InnerTerms = rule { oneOrMore(Var | Const).separatedBy(",") ~> ( x => ExpressionList(x.toList) ) }
def FunctSymbol = rule { capture(LowerCaseString) ~> ((x: String) => x) }
def Var = rule { capture(UpperCaseWord) ~> ((x: String) => Variable(x)) }
def Const = rule { capture(LowerCaseWord) ~> ((x: String) => Constant(x)) }
def LowerCaseWord = rule { CharPredicate.LowerAlpha ~ zeroOrMore(CharPredicate.AlphaNum | "_") }
def number = rule { oneOrMore(CharPredicate.Digit) }
def UpperCaseWord = rule { CharPredicate.UpperAlpha ~ zeroOrMore(CharPredicate.AlphaNum | "_") }
where Atom, ExpressionList, Variable, Constant are custom case classes. Naturally, this gets me to p(q(x,y),z), but not to p(q(r(x),y),z)