ometa M <: Parser { escapeChar = '\\' char:c -> ['\\', c].join("") | char:c -> c, whitespace = (' ' | '\t' | '\n' | '\r'), _ = whitespace+, __ = whitespace*, idFirst = letter | '_', idRest = idFirst | digit, id = firstAndRest(#idFirst, #idRest):m -> ['id', m.join('')], reference = id, constantReference = ("nil" | "false" | "true"):m -> ['constantReference', m], pseudoVariableReference = ("self" | "thisContext"):m -> ['pseudoVariableReference', m], reservedIdentifier = pseudoVariableReference | constantReference, symbolInArrayLiteral = unaryMessageSelector ~constantReference | keywordMessageSelector | binaryMessageSelector, integerLiteral = digit+:d -> ['integer', d.join('')], characterLiteral = "$" char, stringLiteral = '\"' (~'\"' escapeChar)*:s '\"' -> ['string', s.join("")], symbolLiteral = "#" (symbolInArrayLiteral | constantReference | stringLiteral), literal = constantReference | integerLiteral | characterLiteral | stringLiteral | symbolLiteral, nestedExpression = "(" statement __ ")", operand = literal | reference | nestedExpression, unaryMessageSelector = id:m -> m, unaryMessage = unaryMessageSelector:m -> m, unaryMessageChain = (__ unaryMessage)*:m -> m, binarySelectorChar = <'~' | '!' | '@' | '%' | '&' | '*' | '-' | '+' | '=' | "|" | "\\" | "<" | ">" | "," | "?" | "/">, binaryMessageSelector = binarySelectorChar:l binarySelectorChar?:r -> { r ? l + r : l }, binaryMessageOperand = operand:o unaryMessageChain:m -> [o, m], binaryMessage = binaryMessageSelector:s __ binaryMessageOperand:o -> [s, o], binaryMessageChain = (__ binaryMessage)*, keyword = id:x ':' -> ['keyword', x], keywordMessageSelector = (keyword keyword*):s -> s, keywordMessageArgument = binaryMessageOperand:o binaryMessageChain:c -> [o, c], keywordMessageSegment = keyword:k __ keywordMessageArgument:a -> [k, a], keywordMessage = keywordMessageSegment (__ keywordMessageSegment)*, messageChain = (unaryMessage:a unaryMessageChain:b binaryMessageChain:c keywordMessage?:d):m -> ['messageChainUnary', a, b, c, d] | binaryMessage:m binaryMessageChain:c keywordMessage?:km -> { km ? [m, c, km] : [m, c] } | keywordMessage:m -> m, expression = operand:o (__ messageChain:m)? -> ['expr', o, m ? m : null] } M.matchAll('nil isNil: true or: false', 'expression')