def _create_parser() -> ParserElement: # operators in the format later used by infixNotation operator_list = [ (None, 2, opAssoc.LEFT, BooleanAndOperation._create_from_implicit_tokens), (CaselessKeyword('not') | "~" | "!", 1, opAssoc.RIGHT, BooleanNotOperation._create_from_tokens), (CaselessKeyword('and') | "&", 2, opAssoc.LEFT, BooleanAndOperation._create_from_tokens), (CaselessKeyword('xor') | "^", 2, opAssoc.LEFT, BooleanXorOperation._create_from_tokens), (CaselessKeyword('or') | "|", 2, opAssoc.LEFT, BooleanOrOperation._create_from_tokens), ] # terms (atoms) that will be combined with the boolean operators term_list = [ (CaselessKeyword('tag'), TagFilterTerm._create_from_tokens), (CaselessKeyword('ingr'), IngredientFilterTerm._create_from_tokens), (CaselessKeyword('unit'), UnitFilterTerm._create_from_tokens), (None, AnyFilterTerm._create_from_tokens), ] # extract keywords that can operator_expressions = [om[0] for om in operator_list if om[0] is not None] term_expressions = [tm[0] for tm in term_list if tm[0] is not None] reserved_expressions = operator_expressions + term_expressions # quoted string indicates exact macthc quoted_filter_string = (QuotedString('"', escChar='\\') | QuotedString("'", escChar='\\')).setResultsName('string') # quoted_filter_string.setDebug(True) quoted_filter_string.setName("quoted_filter_string") quoted_filter_string.setParseAction(ExactFilterString._create_from_tokens) # not quoted string is inexact match, can't contain whitespace or be an operator unquoted_filter_string = ~MatchFirst(reserved_expressions) + Regex(r'[^\s\(\)]+', flags=re.U).setResultsName('string') # unquoted_filter_string.setDebug(True) unquoted_filter_string.setName("unquoted_filter_string") unquoted_filter_string.setParseAction(FuzzyFilterString._create_from_tokens) # regular expressions aren't parsed in the grammar but delegated to python re.compile in the parser action regex_filter_string = QuotedString('/', escChar='\\') regex_filter_string.setName("regex_filter_string") regex_filter_string.setParseAction(RegexFilterString._create_from_tokens) # unquoted_filter_string must be last, so that initial quotes are handled correctly filter_string = regex_filter_string | quoted_filter_string | unquoted_filter_string filter_string.setParseAction(lambda toks: toks[0]) filter_terms = [] for prefix_expression, term_action in term_list: if prefix_expression is not None: filter_term = Combine(prefix_expression + ':' + filter_string.setResultsName("filter_string")) filter_term.setName("filter_term_"+str(prefix_expression.match)) else: filter_term = filter_string.setResultsName("filter_string") filter_term.setName("filter_term_None") # filter_term.setDebug(True) filter_term.addParseAction(term_action) filter_terms.append(filter_term) filter_term = MatchFirst(filter_terms) filter_expr = infixNotation(filter_term, operator_list) return filter_expr
def _define_grammar(self): '''define the grammar to be used, and add actions''' self._define_actions() eol = LineEnd().suppress() white = Optional(White()).suppress() begin = Keyword('begin').suppress() end = Keyword('end').suppress() comment = (Literal('#') + restOfLine).suppress() data_value = Combine(OneOrMore(CharsNotIn('#\n\r'))) data_line = (LineStart() + white + Optional(data_value) + Optional(comment) + eol) block_name = Word(alphas, alphanums + '_') begin_block = (LineStart() + begin + block_name + Optional(comment) + eol) end_block = LineStart() + end + block_name + Optional(comment) + eol junk = ZeroOrMore(LineStart() + white + NotAny(begin) + restOfLine + eol).suppress() data = Group(ZeroOrMore(NotAny(end) + data_line)) block_def = begin_block + data + end_block block_defs = junk + OneOrMore(block_def + junk) self._grammar = block_defs begin_block.addParseAction(self._begin_block_action) end_block.addParseAction(self._end_block_action) data_value.addParseAction(self._data_value_action)
eol = LineEnd().suppress() begin = Keyword("begin").suppress() end = Keyword("end").suppress() comment = (Literal("#") + restOfLine).suppress() data_value = Combine(OneOrMore(CharsNotIn("#\n\r"))) data = LineStart() + Optional(data_value) + Optional(comment) + eol block_name = Word(alphas, alphanums + "_") begin_block = LineStart() + begin + block_name + Optional(comment) + eol end_block = LineStart() + end + block_name + Optional(comment) + eol junk = ZeroOrMore(LineStart() + NotAny(begin) + restOfLine + eol).suppress() block_def = begin_block + Group(ZeroOrMore(NotAny(end) + data)) + end_block block_defs = junk + OneOrMore(block_def + junk) begin_block.addParseAction(create_block) end_block.addParseAction(finish_block) data_value.addParseAction(handle_data) test_str = """ bla bla begin block_1 # bla bla 0.17 # suspicious value # comment line -7.34 end block_1 # and noe the second block begin block_2 17.34 11.8 end block_2 """
def _setup_QASMParser(): """ Routine to initialise and return parsing blocks """ class _Op: """ Class to set up quantum operations """ def __init__(self, name, argParser, version="OPENQASM 2.0", qop=False, keyOverride=None): global cops global qops global _reservedKeys if name in qops or name in cops: raise IOError(dupTokenWarning.format("Operation", name)) self.operation = name if keyOverride is not None: self.parser = (keyOverride + argParser).addParseAction( lambda s, l, t: _override_keyword(t, name)) else: self.parser = CaselessKeyword(name)("keyword") + argParser self.version = parse_version(version) self.parser.addParseAction( lambda s, l, t: _set_version(t, self.version)) _reservedKeys.append(name) if qop: qops[name] = self else: cops[name] = self class _Routine(): """ Class to set up quantum gates, circuits, etc. """ def __init__(self, name, pargs=False, spargs=False, gargs=False, qargs=False, returnables=False, prefixes=None, version="OPENQASM 2.0"): global blocks global _reservedKeys if name in qops or name in cops: raise IOError(dupTokenWarning.format("Routine", name)) self.operation = name self.parser = Keyword(name)("keyword") + validName("gateName") if prefixes: localPrefixParser = Each(map(Optional, map( Keyword, prefixes))).addParseAction(prefix_setter) else: localPrefixParser = prefixParser self.parser = localPrefixParser + self.parser # Handle different args req = [] if pargs: req.append(Optional(pargParser)("pargs")) if spargs: req.append(Optional(spargParser)("spargs")) if gargs: req.append(Optional(gargParser)("gargs")) self.parser = self.parser + Each(req) if qargs: self.parser = self.parser + qargParser("qargs") if returnables: self.parser = self.parser + Optional(returnParser) self.version = parse_version(version) self.parser.addParseAction( lambda s, l, t: _set_version(t, self.version)) _reservedKeys.append(name) blocks[name] = self class _Block(): """ Class to set up blocks such as if, for, etc. """ def __init__(self, name, detParser, version="OPENQASM 2.0"): global blocks global _reservedKeys self.operation = name self.parser = Keyword(name)("keyword") + detParser self.version = parse_version(version) self.parser.addParseAction( lambda s, l, t: _set_version(t, self.version)) _reservedKeys.append(name) blocks[name] = self sign = Word("+-", exact=1) number = Word(nums) expo = Combine(CaselessLiteral("e") + Optional(sign) + number).setResultsName("exponent") pi = CaselessKeyword("pi") bitstring = Combine(OneOrMore(oneOf("0 1")) + Literal("b")) integer = Combine(number + Optional(expo)) real = Combine( Optional(sign) + (("." + number) ^ (number + "." + Optional(number))) + Optional(expo)) validName = Forward() lineEnd = Literal(";") _is_ = Keyword("to").suppress() _in_ = Keyword("in") _to_ = Literal("->").suppress() commentSyntax = "//" commentOpenStr = "/*" commentCloseStr = "*/" commentOpenSyntax = Literal(commentOpenStr) commentCloseSyntax = Literal(commentCloseStr) dirSyntax = "***" dirOpenStr = f"{dirSyntax} begin" dirCloseStr = f"{dirSyntax} end" dirSyntax = Keyword(dirSyntax) dirOpenSyntax = CaselessLiteral(dirOpenStr) dirCloseSyntax = CaselessLiteral(dirCloseStr) intFunc = oneOf("abs powrem countof fllog") realFunc = oneOf("abs powrem arcsin arccos arctan sin cos tan exp ln sqrt") boolFunc = oneOf("andof orof xorof") inL, inS, inR = map(Suppress, "[:]") vBar = Suppress("|") bSlash = Suppress("\\") brL, brR = map(Suppress, "()") intExp = Forward() realExp = Forward() boolExp = Forward() index = intExp.setResultsName("index") interval = Optional(intExp.setResultsName("start"), default=None) + inS \ + Optional(intExp.setResultsName("end"), default=None) \ + Optional(inS + Optional(intExp.setResultsName("step"), default=1)) interRef = Group(inL + interval + inR) loopRef = Group( inL + intExp.setResultsName("start") + inS + intExp.setResultsName("end") + Optional(inS + Optional(intExp.setResultsName("step"), default=1)) + inR) ref = inL + Group(delimitedList(index ^ interval))("ref") + inR regNoRef = validName("var") regRef = Group(validName("var") + Optional(ref)) regMustRef = Group(validName("var") + ref) regListNoRef = Group(delimitedList(regNoRef)) regListRef = Group(delimitedList(regRef)) inPlaceAlias = vBar + regListRef + vBar validQarg = regRef | inPlaceAlias aliasQarg = Group(regRef) | inPlaceAlias inPlaceCreg = bSlash + delimitedList(regRef | bitstring) + bSlash validCreg = (regRef | inPlaceCreg) def set_maths_type(toks, mathsType): """ Set logical or integer or floating point """ toks["type"] = mathsType intVar = integer | regRef realVar = real | integer | pi | regRef boolVar = interRef | regRef | realExp | intExp | validCreg | bitstring intFuncVar = (intFunc + brL + Group(Optional(delimitedList(intVar)))("args") + brR).setParseAction(Function) realFuncVar = ((realFunc ^ intFunc) + brL + Group(Optional(delimitedList(realVar)))("args") + brR).setParseAction(Function) boolFuncVar = (boolFunc + brL + Group(Optional(delimitedList(boolVar)))("args") + brR).setParseAction(Function) mathOp = [(oneOf("- +"), 1, opAssoc.RIGHT, Binary), (oneOf("^"), 2, opAssoc.LEFT, Binary), (oneOf("* / div"), 2, opAssoc.LEFT, Binary), (oneOf("+ -"), 2, opAssoc.LEFT, Binary)] logOp = [(oneOf("! not"), 1, opAssoc.RIGHT, Binary), (oneOf("and or xor"), 2, opAssoc.LEFT, Binary), (oneOf("< <= == != >= >"), 2, opAssoc.LEFT, Binary), (oneOf("in"), 2, opAssoc.LEFT, Binary)] intExp <<= infixNotation( intFuncVar | intVar, mathOp).setParseAction(lambda s, l, t: set_maths_type(t, "int")) realExp <<= infixNotation( realFuncVar | realVar, mathOp).setParseAction(lambda s, l, t: set_maths_type(t, "float")) boolExp <<= infixNotation( boolFuncVar | boolVar, logOp).setParseAction(lambda s, l, t: set_maths_type(t, "bool")) mathExp = intExp ^ realExp ^ boolExp cregExp = bitstring("bit") ^ validCreg("reg") prefixes = ["unitary"] callMods = ["CTRL", "INV"] def prefix_setter(toks): """ Pull out prefixes of gate calls and add them into list """ for prefix in prefixes: toks[prefix] = prefix in toks.asList() prefixParser = Each(map(Optional, map(Keyword, prefixes))).addParseAction(prefix_setter) pargParser = brL + delimitedList(validName)("pargs") + brR spargParser = inL + delimitedList(validName)("spargs") + inR gargParser = ungroup( nestedExpr("<", ">", delimitedList(ungroup(validName)), None)) qargParser = delimitedList(regRef) callQargParser = delimitedList(validQarg) callPargParser = brL + delimitedList(realExp) + brR callSpargParser = inL + delimitedList(intExp) + inR fullArgParser = Each( (Optional(pargParser("pargs")), Optional(spargParser("spargs")), Optional(gargParser("gargs")))) callArgParser = Each( (Optional(callPargParser("pargs")), Optional(callSpargParser("spargs")), Optional(gargParser("gargs")))) returnParser = Optional(_to_ + validCreg("byprod")) modifiers = ZeroOrMore(Combine(oneOf(callMods) + Suppress("-"))) commentLine = Literal(commentSyntax).suppress() + restOfLine("comment") commentBlock = cStyleComment("comment").addParseAction( removeQuotes).addParseAction(removeQuotes) comment = commentLine | commentBlock comment.addParseAction(lambda s, l, t: _set_version(t, (0, 0, 0))) directiveName = Word(alphas).setParseAction(downcaseTokens) directiveArgs = CharsNotIn(";") _Op("directive", directiveName("directive") + Suppress(White() * (1, )) + directiveArgs("args"), version="REQASM 1.0", keyOverride=(~dirOpenSyntax + ~dirCloseSyntax + dirSyntax)) def split_args(toks): """ Split directive arguments out """ toks[0]["keyword"] = "directive" toks[0]["args"] = toks[0]["args"].strip().split(" ") directiveStatement = directiveName("directive") + restOfLine("args") + \ Group(ZeroOrMore(Combine(Optional(White(" ")) + ~dirCloseSyntax + Word(printables+" "))))("block") directiveBlock = ungroup( nestedExpr( dirOpenSyntax, dirCloseSyntax, content=directiveStatement, ignoreExpr=(comment | quotedString )).setWhitespaceChars("\n").setParseAction(split_args)) directiveBlock.addParseAction(lambda s, l, t: _set_version(t, (2, 1, 0))) # Programming lines _Op("version", Empty(), version=(0, 0, 0), keyOverride=Combine( oneOf(versions)("type") + White() + real("versionNumber"))("version")) _Op("include", quotedString("file").addParseAction(removeQuotes)) # Gate-like structures _Op("opaque", validName("name") + fullArgParser + Optional(qargParser("qargs")) + returnParser, keyOverride=prefixParser + "opaque") _Routine("gate", pargs=True, qargs=True) _Routine("circuit", pargs=True, qargs=True, spargs=True, returnables=True, version="REQASM 1.0") # Variable-like structures _Op("creg", regRef("arg")) _Op("qreg", regRef("arg")) _Op("cbit", Group(regNoRef)("arg"), version="REQASM 1.0") _Op("qbit", Group(regNoRef)("arg"), version="REQASM 1.0") _Op("defAlias", regMustRef("alias"), keyOverride="alias", version="REQASM 1.0") # No more on-definition aliases _Op("alias", regRef("alias") + _is_ + aliasQarg("target"), keyOverride="set", version="REQASM 1.0") _Op("val", validName("var") + Literal("=").suppress() + mathExp("val"), version="REQASM 1.0") _Op("set", (Group(regRef)("var") ^ inPlaceCreg("var")) + Literal("=").suppress() + cregExp("val"), version="REQASM 1.0") # Operations-like structures _Op("measure", regRef("qreg") + _to_ + regRef("creg"), qop=True) _Op("barrier", regListNoRef("args")) _Op("output", regRef("value"), qop=True, version="REQASM 1.0") _Op("reset", regRef("qreg")) _Op("exit", Empty(), version="REQASM 1.0") _Op("free", validName("target"), version="REQASM 1.0") _Op("next", validName("loopVar"), qop=True, version="REQASM 1.0") _Op("finish", (Literal("quantum process") | validName)("loopVar"), qop=True, version="REQASM 1.0") _Op("end", validName("process"), qop=True, version="REQASM 1.0") # Special gate call handler callGate = Combine(Group(modifiers)("mods") + \ validName("gate")) + \ callArgParser + \ callQargParser("qargs").addParseAction(lambda s, l, t: _override_keyword(t, "call")) + \ returnParser callGate.addParseAction(lambda s, l, t: _set_version(t, (1, 2, 0))) # Block structures _Block("for", validName("var") + _in_ + loopRef("range"), version="REQASM 1.0") _Block("if", "(" + boolExp("cond") + ")", version="REQASM 1.0") _Block("while", "(" + boolExp("cond") + ")", version="OMEQASM 1.0") qopsParsers = list(map(lambda qop: qop.parser, qops.values())) + [callGate, directiveBlock] blocksParsers = list(map(lambda block: block.parser, blocks.values())) _Op("if", blocks["if"].parser + Group(Group(Group(Or(qopsParsers))))("block"), version="OPENQASM 2.0", keyOverride=Empty()) _Op("for", blocks["for"].parser + Group(Group(Group(Or(qopsParsers))))("block"), version="REQASM 1.0", keyOverride=Empty()) _Op("while", blocks["while"].parser + Group(Group(Group(Or(qopsParsers))))("block"), version="OMEQASM 1.0", keyOverride=Empty()) # Set-up line parsers reservedNames = Or(map(Keyword, _reservedKeys)) validName <<= (~reservedNames) + Word(alphas, alphanums + "_") copsParsers = list(map(lambda cop: cop.parser, cops.values())) operations = (( (Or(copsParsers) ^ Or(qopsParsers)) | # Classical/Quantum Operations callGate | # Gate parsers White() # Blank Line ) + lineEnd.suppress()) ^ directiveBlock # ; or Directives validLine = Forward() codeBlock = nestedExpr("{", "}", Suppress(White()) ^ Group(validLine), (quotedString)) validLine <<= ( ((operations + Optional(comment)) ^ (Or(blocksParsers) + codeBlock("block") + Optional(lineEnd)) ^ comment)) # Whole line comment testLine = Forward() dummyCodeBlock = nestedExpr( "{", "}", testLine, (directiveBlock | quotedString | comment)) + Optional(lineEnd) ignoreSpecialBlocks = (~commentOpenSyntax + ~commentCloseSyntax + ~dirOpenSyntax + ~dirCloseSyntax) testLine <<= ( comment | # Comments directiveBlock | # Directives (ignoreSpecialBlocks + ZeroOrMore(CharsNotIn("{}")) + dummyCodeBlock) | # Block operations (ignoreSpecialBlocks + ZeroOrMore(CharsNotIn("{};")) + lineEnd) ) # QASM Instructions testKeyword = (dirSyntax.setParseAction( lambda s, l, t: _override_keyword(t, "directive")) | Word(alphas)("keyword")) code = (Group(directiveBlock)) | Group(validLine) return code, testLine, testKeyword, reservedNames, mathExp
eol = LineEnd().suppress() begin = Keyword('begin').suppress() end = Keyword('end').suppress() comment = (Literal('#') + restOfLine).suppress() data_value = Combine(OneOrMore(CharsNotIn('#\n\r'))) data = LineStart() + Optional(data_value) + Optional(comment) + eol block_name = Word(alphas, alphanums + '_') begin_block = LineStart() + begin + block_name + Optional(comment) + eol end_block = LineStart() + end + block_name + Optional(comment) + eol junk = ZeroOrMore(LineStart() + NotAny(begin) + restOfLine + eol).suppress() block_def = begin_block + Group(ZeroOrMore(NotAny(end) + data)) + end_block block_defs = junk + OneOrMore(block_def + junk) begin_block.addParseAction(create_block) end_block.addParseAction(finish_block) data_value.addParseAction(handle_data) test_str = ''' bla bla begin block_1 # bla bla 0.17 # suspicious value # comment line -7.34 end block_1 # and noe the second block begin block_2 17.34 11.8 end block_2 '''
expr = Forward() ########## # Number # ########## def number_parse_action(instring, tokensStart, retTokens): parsed_values = retTokens[0] return types.Number(float(parsed_values)) number = Combine(Word(nums) + Optional(Literal('.') + Word(nums))) number.addParseAction(number_parse_action) ########## # String # ########## single_quote_string = QuotedString('\'', escChar='\\') double_quote_string = QuotedString('"', escChar='\\') def string_parse_action(instring, tokensStart, retTokens): parsed_values = retTokens[0] return types.String(parsed_values) string = single_quote_string | double_quote_string