def message_type_definition() -> Token: first_aspect = Keyword("First") - Keyword("=>") - mathematical_expression() first_aspect.setParseAction(parse_aspect) length_aspect = Keyword("Length") - Keyword( "=>") - mathematical_expression() length_aspect.setParseAction(parse_aspect) component_aspects = Keyword("with") - delimitedList(first_aspect | length_aspect) component_aspects.setParseAction(parse_aspects) then = locatedExpr( Keyword("then") - (Keyword("null") | unqualified_identifier()) - Group(Optional(component_aspects)) - Group(Optional(value_constraint()))) then.setParseAction(parse_then) then_list = then + ZeroOrMore(comma() - then) then_list.setParseAction(lambda t: [t.asList()]) component_item = (~Keyword("end") + ~CaselessKeyword("Message") - unqualified_identifier() + Literal(":") - qualified_identifier() - Optional(then_list) - semicolon()) component_item.setParseAction(lambda t: Component(t[0], t[2], t[3]) if len(t) >= 4 else Component(t[0], t[2])) component_item.setName("Component") null_component_item = Keyword("null") - then - semicolon() null_component_item.setParseAction(lambda t: Component(None, None, [t[1]])) null_component_item.setName("NullComponent") component_list = Group( Optional(null_component_item) - component_item - ZeroOrMore(component_item)) component_list.setParseAction(lambda t: t.asList()) return (Keyword("message") - component_list - Keyword("end message") | Keyword("null message")).setName("Message")
def integer_type_definition() -> Token: range_type_aspects = Keyword("with") - size_aspect() range_type_aspects.setParseAction(parse_aspects) range_type_definition = (Keyword("range") - mathematical_expression() - Suppress(Literal("..")) - mathematical_expression() - range_type_aspects) range_type_definition.setName("RangeInteger") modular_type_definition = Keyword("mod") - mathematical_expression() modular_type_definition.setName("ModularInteger") return range_type_definition | modular_type_definition
def __init__(self, basedir: str = '.') -> None: self.__basedir = basedir self.__specifications: Dict[str, Specification] = {} self.__pdus: Dict[str, PDU] = {} self.__refinements: Dict[str, Refinement] = {} # Generic comma = Suppress(Literal(',')) comma.setName('","') semicolon = Suppress(Literal(';')) semicolon.setName('";"') # Comments comment = Regex(r'--.*') # Names identifier = WordStart(alphanums) + Word(alphanums + '_') + WordEnd(alphanums + '_') identifier.setParseAction(verify_identifier) identifier.setName('Identifier') qualified_identifier = Optional(identifier + Literal('.')) - identifier qualified_identifier.setParseAction(lambda t: ''.join(t.asList())) attribute_designator = Keyword('First') | Keyword('Last') | Keyword( 'Length') attribute_reference = identifier + Literal('\'') - attribute_designator attribute_reference.setParseAction(parse_attribute) attribute_reference.setName('Attribute') name = attribute_reference | identifier name.setName('Name') # Literals numeral = Word(nums) + ZeroOrMore(Optional(Word('_')) + Word(nums)) numeral.setParseAction( lambda t: int(''.join(t.asList()).replace('_', ''))) extended_digit = Word(nums + 'ABCDEF') based_numeral = extended_digit + ZeroOrMore( Optional('_') + extended_digit) based_literal = numeral + Literal('#') - based_numeral - Literal('#') based_literal.setParseAction( lambda t: int(t[2].replace('_', ''), int(t[0]))) numeric_literal = based_literal | numeral numeric_literal.setParseAction(lambda t: Number(t[0])) numeric_literal.setName('Number') literal = numeric_literal # Operators mathematical_operator = (Literal('**') | Literal('+') | Literal('-') | Literal('*') | Literal('/')) relational_operator = (Keyword('<=') | Keyword('>=') | Keyword('=') | Keyword('/=') | Keyword('<') | Keyword('>')) logical_operator = Keyword('and') | Keyword('or') # Expressions mathematical_expression = Forward() relation = mathematical_expression + relational_operator - mathematical_expression relation.setParseAction(parse_relation) relation.setName('Relation') logical_expression = infixNotation( relation, [(logical_operator, 2, opAssoc.LEFT, parse_logical_expression)]) logical_expression.setName('LogicalExpression') term = Keyword('null') | literal | name term.setParseAction(parse_term) mathematical_expression << infixNotation( term, [(mathematical_operator, 2, opAssoc.LEFT, parse_mathematical_expression)]) mathematical_expression.setName('MathematicalExpression') # Type Refinement value_constraint = Keyword('if') - logical_expression value_constraint.setParseAction(lambda t: t[1]) type_refinement_definition = ( Keyword('new') - qualified_identifier - Suppress(Literal('(')) - identifier - Suppress(Literal('=>')) - (Keyword('null') | qualified_identifier) - Suppress(Literal(')')) - Optional(value_constraint)) type_refinement_definition.setName('Refinement') # Integer Types size_aspect = Keyword('Size') - Keyword('=>') - mathematical_expression size_aspect.setParseAction(parse_aspect) range_type_aspects = Keyword('with') - size_aspect range_type_aspects.setParseAction(parse_aspects) range_type_definition = (Keyword('range') - mathematical_expression - Suppress(Literal('..')) - mathematical_expression - range_type_aspects) range_type_definition.setName('RangeInteger') modular_type_definition = Keyword('mod') - mathematical_expression modular_type_definition.setName('ModularInteger') integer_type_definition = range_type_definition | modular_type_definition # Enumeration Types enumeration_literal = name positional_enumeration = enumeration_literal + ZeroOrMore( comma - enumeration_literal) positional_enumeration.setParseAction( lambda t: [(k, Number(v)) for v, k in enumerate(t.asList())]) element_value_association = enumeration_literal + Keyword( '=>') - numeric_literal element_value_association.setParseAction(lambda t: (t[0], t[2])) named_enumeration = (element_value_association + ZeroOrMore(comma - element_value_association)) boolean_literal = Keyword('True') | Keyword('False') boolean_literal.setParseAction(lambda t: t[0] == 'True') boolean_aspect_definition = Optional(Keyword('=>') - boolean_literal) boolean_aspect_definition.setParseAction(lambda t: (t if t else ['=>', True])) always_valid_aspect = Literal( 'Always_Valid') - boolean_aspect_definition always_valid_aspect.setParseAction(parse_aspect) enumeration_aspects = Keyword('with') - delimitedList( size_aspect | always_valid_aspect) enumeration_aspects.setParseAction(parse_aspects) enumeration_type_definition = ( Literal('(') - (named_enumeration | positional_enumeration) - Literal(')') - enumeration_aspects) enumeration_type_definition.setName('Enumeration') # Array Type unconstrained_array_definition = Keyword('array of') + name array_type_definition = unconstrained_array_definition array_type_definition.setName('Array') # Message Type first_aspect = Keyword('First') - Keyword( '=>') - mathematical_expression first_aspect.setParseAction(parse_aspect) length_aspect = Keyword('Length') - Keyword( '=>') - mathematical_expression length_aspect.setParseAction(parse_aspect) component_aspects = Keyword('with') - delimitedList(first_aspect | length_aspect) component_aspects.setParseAction(parse_aspects) then = (Keyword('then') - (Keyword('null') | identifier) - Group(Optional(component_aspects)) - Group(Optional(value_constraint))) then.setParseAction(parse_then) then_list = then + ZeroOrMore(comma - then) then_list.setParseAction(lambda t: [t.asList()]) component_list = Forward() message_type_definition = Keyword( 'message') - component_list - Keyword('end message') message_type_definition.setName('Message') component_item = (~Keyword('end') + ~CaselessKeyword('Message') - identifier + Literal(':') - name - Optional(then_list) - semicolon) component_item.setParseAction(lambda t: Component(t[0], t[2], t[3]) if len(t) >= 4 else Component(t[0], t[2])) component_item.setName('Component') null_component_item = Keyword('null') - then - semicolon null_component_item.setParseAction( lambda t: Component(t[0], '', [t[1]])) null_component_item.setName('NullComponent') component_list << (Group( Optional(null_component_item) - component_item - ZeroOrMore(component_item))) component_list.setParseAction(lambda t: t.asList()) # Types type_definition = (enumeration_type_definition | integer_type_definition | message_type_definition | type_refinement_definition | array_type_definition) type_declaration = (Keyword('type') - identifier - Keyword('is') - type_definition - semicolon) type_declaration.setParseAction(parse_type) # Package basic_declaration = type_declaration package_declaration = (Keyword('package') - identifier - Keyword('is') - Group(ZeroOrMore(basic_declaration)) - Keyword('end') - name - semicolon) package_declaration.setParseAction( lambda t: Package(t[1], t[3].asList())) # Context context_item = Keyword('with') - identifier - semicolon context_item.setParseAction(lambda t: t[1]) context_clause = ZeroOrMore(context_item) context_clause.setParseAction(lambda t: Context(t.asList())) # Specification specification = Optional(context_clause + package_declaration) specification.setParseAction(lambda t: Specification(t[0], t[1]) if len(t) == 2 else None) # Grammar self.__grammar = specification + StringEnd() self.__grammar.setParseAction(self.__evaluate_specification) self.__grammar.ignore(comment)
def model_grammar(): """ Construct a parser for winBugs/openBugs/JAGS models. Returns *parser*, which is a *pyaparsing.ParserElement, with the *parser.parserString()* method. Be sure to strip comments from the string prior to parsing, so that the grammar can be a little simpler. """ ###factor = Forward().setName('factor') # for right-to-left parsing expression = Forward().setName('expr') group = Forward().setName('group') # start:stop used for indexing and for loops inner_range = Optional (expression + Optional(Literal(":") + expression)) paren_range = Literal("(").suppress() + inner_range + Literal(")").suppress() slice = inner_range | paren_range paren_range.setName('(slice)') inner_range.setName('slice').setParseAction( lambda s,l,t: [(SLICE,(NONE,),(NONE,)) if len(t)==0 else (SLICE,t[0],t[2]) if len(t)>1 else t[0]]) # indexing subscripts = slice + ZeroOrMore(Literal(',').suppress() + slice) index = Literal('[').suppress() + subscripts + Literal(']').suppress() indexed_variable = variable + Optional(index) subscripts.setName('subs') index.setName('index') indexed_variable.setName('deref').setParseAction( lambda s,l,t: [(DEREF,t[0],t[1:])]) # arithmetic muldiv = Literal('*') | Literal('/') addsub = Literal('+') | Literal('-') ###exponent = Literal('^') pars = expression + ZeroOrMore(Literal(',').suppress() + expression) function = variable + Literal('(') + Optional(pars) + Literal(')') paren = Literal('(') + expression + Literal(')') value = constant + Empty() atom = Optional("-") + (function | indexed_variable | value | paren ) ###factor << (atom | ZeroOrMore (exponent + factor)) ###term = factor + ZeroOrMore(muldiv + factor) term = atom + ZeroOrMore(muldiv + atom) expression << (term + ZeroOrMore(addsub + term)) paren.setName('paren').setParseAction( lambda s,l,t: [t[1]]) value.setName('value').setParseAction( lambda s,l,t: [(CONST, t[0])]) function.setName('apply').setParseAction( lambda s,l,t: [(APPLY, t[0], t[2:-1])]) atom.setName('atom').setParseAction( lambda s,l,t: [(UNARY, t[0], t[1]) if len(t)>1 else t[0]]) ###factor.setName('factor').setParseAction(lambda s,l,t: [_binop(t)]) term.setName('term').setParseAction( lambda s,l,t: [_binop(t)]) expression.setName('expr').setParseAction( lambda s,l,t: [_binop(t)]) # priors look like dname(p1,p2,...) with optional qualifier T(left,right) # to set the bounds on the prior. Since left/right are optional, the # function parser can't be used, and we need a special bounds term to # parse this form. bounds_limit = expression | Empty() bounds_function = (variable + Literal('(') + bounds_limit + Literal(',') + bounds_limit + Literal(')')) bounds = bounds_function | Empty() bounds_limit.setName('limit').setParseAction( lambda s,l,t: [(t[0] if len(t) else (NONE,))]) bounds.setName('trunc').setParseAction( lambda s,l,t: [(APPLY,t[0],[t[2],t[4]]) if len(t) else (NONE,)]) # Funky assignment lhs functions, such as: # logit(t) <- alpha; D(C[5],t) <- PER1 * C[7] - R*kT1*C[1] lhs_function = variable + Literal('(') + indexed_variable \ + ZeroOrMore(Literal(',') + indexed_variable) + Literal(')') lhs_function.setName('f(lhs)').setParseAction( lambda s,l,t: [(APPLY, t[0], t[2::2])]) # statements assignment = (lhs_function | indexed_variable) + Literal("<-") + expression prior = indexed_variable + Literal("~") + function + bounds loop = (Keyword("for") + Literal("(") + variable + Keyword("in") + expression + Literal(":") + expression + Literal(")") + group) assignment.setName('assign').setParseAction( lambda s,l,t: [(ASSIGN, t[0], t[2])]) prior.setName('prior').setParseAction( lambda s,l,t: [(PRIOR, t[0], t[2], t[3])]) loop.setName('loop').setParseAction( lambda s,l,t: [(LOOP, t[2], t[4], t[6], t[8:])]) # Note: line breaks are ignored. That means the following are valid: # statement\n # statement;\n # statement; statement\n # statement statement\n # partial statement\n statement completion # Indeed, all of these forms exist in the openBugs example models. #comment = Literal("#[^\n]*") statement = (loop | assignment | prior) + Optional(Literal(';')).suppress() body = ZeroOrMore(statement) group << (Literal("{").suppress() + body + Literal("}").suppress()) model = Keyword("model") + group + StringEnd() model.setName('model').setParseAction( lambda s,l,t: [(MODEL, t[1:])]) if 0: # Debug all_terms = ( model, group, body, statement, loop, prior, assignment, expression, term, atom, muldiv, addsub, value, constant, paren, function, pars, indexed_variable, variable, index, subscripts, slice, inner_range, paren_range, ) for s in all_terms: s.setDebug(True) return model