Ejemplo n.º 1
0
 def failToken(s):
     """
     pyparsing hack to give better error messages,
     "a or b expected" rather than "b expected". 
     """
     t = NoMatch()
     t.setName(s)
     return t
Ejemplo n.º 2
0
def get_match_first(lits, parseAction=None):
    el = MatchFirst(NoMatch())
    for lit in lits:
        el = el.__ior__(lit)
    if parseAction:
        el.setParseAction(parseAction)
    return el
Ejemplo n.º 3
0
 def sreduce(f, l):
     ''' Same as reduce, but handle len 1 and len 0 lists sensibly '''
     if len(l) == 0:
         return NoMatch()
     if len(l) == 1:
         return l[0]
     return reduce(f, l)
Ejemplo n.º 4
0
class Markup:
    def __init__(self, tokens_list):
        self._markup = NoMatch()
        for token in tokens_list:
            self._markup |= token

    def transformString(self, text):
        return self._markup.transformString(text)
Ejemplo n.º 5
0
def make_operations(operand, operators, group_start="(", group_end=")"):
    """
    Build the Pyparsing grammar for the ``operators`` and return it.
    
    :param operand: The Pyparsing grammar for the operand to be handled by
        the ``operators``.
    :param operators: List of quintuples that define the properties of every
        operator.
    
    The order of the ``operators`` describe the precedence of the operators.
    
    Each tuple in ``operators`` are made up of the following five elements,
    which define the operator:
    
    - The Pyparsing expression for the operator.
    - The arity of the operator (1 or 2).
    - The associativity of the operator ("left" or "right"), if it's a binary
      operation; otherwise ``None``.
    - The notation of the operator (prefix, postfix or infix), if it's a binary
      one.
    - Whether the left-hand operand should be the master operand. If ``False``,
      the left- and right-hand operands will be the slave and master ones.
    - The parse action of the operator.
    
    The parse actions for unary operations will receive the named results for 
    the ``operator`` and the ``operand``, while those for binary operations will
    receive the named results for the ``operator`` and the ``master_operand``
    and the ``slave_operand``.
    
    The code for the operatorPrecedence() function in Pyparsing was used as an
    starting point to make this function.
    
    """
    operation = Forward()
    group_start = Suppress(group_start)
    group_end = Suppress(group_end)
    last_expression = operand | (group_start + operation + group_end)

    # The "previous_operators" variable represents the expressions for the
    # previous operators, so it can be used to prevent wrong matches of
    # operators when a higher level operator was expected. This would happen
    # when the string of an operator represents the starting characters of
    # a higher level operator. See Bug #397807.
    previous_operators = NoMatch()

    for (operator_expr, arity, assoc, notation, master_left, pa) in operators:
        final_operator = ~previous_operators + operator_expr
        new_expression = _append_operation(operand, last_expression,
                                           final_operator,
                                           arity, assoc.lower(),
                                           notation.lower(), master_left, pa)
        last_expression = new_expression
        # Updating the list of previous operators, so they won't be matched in
        # higher-level operations:
        previous_operators = previous_operators | operator_expr

    operation << last_expression
    return operation
Ejemplo n.º 6
0
def parse_imp(input):
    # Grammar:
    #
    # <expr> ::= <integer>
    #            true
    #            false
    #            <identifier>
    #
    # <fact> ::= relation(constant, ...).
    #
    # <rule> ::= name(constant, ... ) :- name(constant, ...), ... .
    #

    idChars = alphas + "_+*!=<>"

    pNAME = Word(idChars, idChars + "0123456789")

    pRELATION = pNAME + \
        "(" + Group(pNAME + ZeroOrMore(Suppress(",") + pNAME)) + ")"
    pRELATION.setParseAction(lambda result: (result[0], result[2]))

    pDECL_RELATION = pRELATION + "."
    pDECL_RELATION.setParseAction(lambda result: result[0])

    pRULE = pRELATION + ":-" + \
        Group(pRELATION + ZeroOrMore(Suppress(",") + pRELATION)) + "."
    pRULE.setParseAction(lambda result: (result[0], result[2]))

    pFACT = (pDECL_RELATION ^ NoMatch())

    pQUERY = pRELATION + "?"
    pQUERY.setParseAction(lambda result: (result[0][0], result[0][1]))

    pTOP_QUERY = pQUERY.copy()
    pTOP_QUERY.setParseAction(lambda result: {
        "result": "query",
        "stmt": result[0]
    })

    pTOP_RULE = pRULE.copy()
    pTOP_RULE.setParseAction(lambda result: {"result": "rule", "rule": result})

    pTOP_FACT = pFACT.copy()
    pTOP_FACT.setParseAction(lambda result: {
        "result": "fact",
        "decl": result[0]
    })

    pQUIT = Keyword("#quit")
    pQUIT.setParseAction(lambda result: {"result": "quit"})

    pENV = Keyword("#env")
    pENV.setParseAction(lambda result: {"result": "env"})

    pTOP = (pQUIT ^ pENV ^ pTOP_RULE ^ pTOP_FACT ^ pTOP_QUERY)

    result = pTOP.parseString(input)[0]
    return result  # the first element of the result is the expression
Ejemplo n.º 7
0
def concatenate(tokenlist):
    """
    Склеить несколько токенов из списка
    """
    if len(tokenlist) == 0:
        return NoMatch()

    result = tokenlist[0]
    for token in tokenlist[1:]:
        result |= token

    return result
Ejemplo n.º 8
0
 def update_bind_expr(self):
     self.print_bind_forward << reduce(self._accumulator,
                                       self.current_bind_exprs.values(),
                                       NoMatch()) + StringEnd()
Ejemplo n.º 9
0
    return Group(
        Suppress(backslash) + Literal(key) + Suppress(White()) +
        CharsNotIn(u' \n\t\\') + Suppress(White()))


#
# DEFINE GRAMMAR
#

#phrase      = Word( alphas + u"-.,!? —–‘“”’;:()'\"[]/&%=*…{}" + nums )
phrase = CharsNotIn(u"\n\\")
backslash = Literal(u"\\")
plus = Literal(u"+")

textBlock = Group(
    Optional(NoMatch(), u"text") + Optional(Suppress(newline)) + phrase)
unknown = Group(
    Optional(NoMatch(), u"unknown") + Suppress(backslash) +
    CharsNotIn(u' \n\t\\'))

knownTokens = []

simpleTokens = [
    'p', 'pi', 'b', 'q', 'q1', 'q2', 'q3', 'nb', 'm', 'li', 'd', 'sp', 'mi',
    'pb', 'ip', 'iot', 'io', 'io1', 'io2', 'ip'
]
for st in simpleTokens:
    knownTokens.append(usfmToken(st))

numberTokens = ['c', 'v']
for nt in numberTokens:
Ejemplo n.º 10
0
 def _getForbiddenToken(self):
     return NoMatch()
Ejemplo n.º 11
0
        Optional(value))


def usfmTokenNumber(key):
    return Group(
        Suppress(backslash) + Literal(key) + Suppress(White()) +
        Word(nums + '-()') + Suppress(White()))


# define grammar
# phrase = Word( alphas + "-.,!? —–‘“”’;:()'\"[]/&%=*…{}" + nums )
phrase = CharsNotIn("\n\\")
backslash = Literal("\\")
plus = Literal("+")

textBlock = Group(Optional(NoMatch(), "text") + phrase)
unknown = Group(
    Optional(NoMatch(), "unknown") + Suppress(backslash) +
    CharsNotIn(u' \n\t\\'))
escape = usfmTokenValue("\\", phrase)

id_token = usfmTokenValue("id", phrase)
ide = usfmTokenValue("ide", phrase)
sts = usfmTokenValue("sts", phrase)
h = usfmTokenValue("h", phrase)

mt = usfmTokenValue("mt", phrase)
mt1 = usfmTokenValue("mt1", phrase)
mt2 = usfmTokenValue("mt2", phrase)
mt3 = usfmTokenValue("mt3", phrase)
ms = usfmTokenValue("ms", phrase)
Ejemplo n.º 12
0
def usfmTokenValue(key, value):
    return Group(Suppress(backslash) + Literal(key) + Suppress(White()) + Optional(value))


def usfmTokenNumber(key):
    return Group(Suppress(backslash) + Literal(key) + Suppress(White()) + Word(nums + '-()') + Suppress(White()))


# define grammar
# phrase = Word( alphas + "-.,!? —–‘“”’;:()'\"[]/&%=*…{}" + nums )
phrase = CharsNotIn("\n\\")
backslash = Literal("\\")
plus = Literal("+")

textBlock = Group(Optional(NoMatch(), "text") + phrase)
unknown = Group(Optional(NoMatch(), "unknown") + Suppress(backslash) + CharsNotIn(u' \n\t\\'))

id_token = usfmTokenValue("id", phrase)
ide = usfmTokenValue("ide", phrase)
sts = usfmTokenValue("sts", phrase)
h = usfmTokenValue("h", phrase)

mt = usfmTokenValue("mt", phrase)
mt1 = usfmTokenValue("mt1", phrase)
mt2 = usfmTokenValue("mt2", phrase)
mt3 = usfmTokenValue("mt3", phrase)
ms = usfmTokenValue("ms", phrase)
ms1 = usfmTokenValue("ms1", phrase)
ms2 = usfmTokenValue("ms2", phrase)
mr = usfmTokenValue("mr", phrase)
Ejemplo n.º 13
0
def parse_imp(input):
    # parse a string into an element of the abstract representation

    # Grammar:
    #
    # <expr> ::= <integer>
    #            true
    #            false
    #            <identifier>
    #            ( if <expr> <expr> <expr> )
    #            ( function ( <name ... ) <expr> )
    #            ( <expr> <expr> ... )
    #
    # <decl> ::= var name = expr ;
    #
    # <stmt> ::= if <expr> <stmt> else <stmt>
    #            while <expr> <stmt>
    #            name <- <expr> ;
    #            print <expr> ;
    #            <block>
    #
    # <block> ::= { <decl> ... <stmt> ... }
    #
    # <toplevel> ::= <decl>
    #                <stmt>
    #

    idChars = alphas + "_+*-/?!=<>"

    pIDENTIFIER = Word(idChars, idChars + "0123456789")
    #### NOTE THE DIFFERENCE
    pIDENTIFIER.setParseAction(
        lambda result: EPrimCall(oper_deref, [EId(result[0])]))

    pIDENTIFIERS = ZeroOrMore(pIDENTIFIER)
    pIDENTIFIERS.setParseAction(lambda result: [result])

    # A name is like an identifier but it does not return an EId...
    pNAME = Word(idChars, idChars + "0123456789")

    pNAMES = ZeroOrMore(pNAME)
    pNAMES.setParseAction(lambda result: [result])

    pINTEGER = Word("0123456789")
    pINTEGER.setParseAction(lambda result: EValue(VInteger(int(result[0]))))

    pBOOLEAN = Keyword("true") | Keyword("false")
    pBOOLEAN.setParseAction(
        lambda result: EValue(VBoolean(result[0] == "true")))

    def escapeString(inStr):
        inStr = inStr[1:-1]
        outStr = ""
        i = 0
        while (i < len(inStr) - 1):
            if (inStr[i] == '\\'):
                if (inStr[i + 1] == '\\' or inStr[i + 1] == '\"'):
                    i += 1
            outStr += inStr[i]
            i += 1
        outStr += inStr[-1]
        return outStr

    pSTRING = quotedString.copy()
    pSTRING.setParseAction(
        lambda result: EValue(VString(escapeString(result[0]))))

    pEXPR = Forward()

    pEXPRS = ZeroOrMore(pEXPR)
    pEXPRS.setParseAction(lambda result: [result])

    pIF = "(" + Keyword("if") + pEXPR + pEXPR + pEXPR + ")"
    pIF.setParseAction(lambda result: EIf(result[2], result[3], result[4]))

    def mkFunBody(params, body):
        bindings = [(p, ERefCell(EId(p))) for p in params]
        return ELet(bindings, body)

    pFUN = "(" + Keyword("function") + "(" + pNAMES + ")" + pEXPR + ")"
    pFUN.setParseAction(
        lambda result: EFunction(result[3], mkFunBody(result[3], result[5])))

    pBINDING = "(" + pNAME + pEXPR + ")"
    pBINDING.setParseAction(lambda result: (result[1], result[2]))

    pBINDINGS = ZeroOrMore(pBINDING)
    pBINDINGS.setParseAction(lambda result: [result])

    pCALL = "(" + pEXPR + pEXPRS + ")"
    pCALL.setParseAction(lambda result: ECall(result[1], result[2]))

    pEXPR << (pINTEGER | pBOOLEAN | pSTRING | pIDENTIFIER | pIF | pFUN | pCALL)

    pDECL_VAR = "var" + pNAME + "=" + pEXPR + ";"
    pDECL_VAR.setParseAction(lambda result: (result[1], result[3]))

    pDECL_ARRAY = "var" + pNAME + "<-" + "(" + "new-array" + pEXPR + ")" + ";"
    pDECL_ARRAY.setParseAction(lambda result: (result[1], EArray(result[5])))

    # hack to get pDECL to match only PDECL_VAR (but still leave room
    # to add to pDECL later)
    pDECL = (pDECL_VAR | pDECL_ARRAY | NoMatch())

    pDECLS = ZeroOrMore(pDECL)
    pDECLS.setParseAction(lambda result: [result])

    pSTMT = Forward()

    pSTMT_IF_1 = "if" + pEXPR + pSTMT + "else" + pSTMT
    pSTMT_IF_1.setParseAction(
        lambda result: EIf(result[1], result[2], result[4]))

    pSTMT_IF_2 = "if" + pEXPR + pSTMT
    pSTMT_IF_2.setParseAction(
        lambda result: EIf(result[1], result[2], EValue(VBoolean(True))))

    pSTMT_WHILE = "while" + pEXPR + pSTMT
    pSTMT_WHILE.setParseAction(lambda result: EWhile(result[1], result[2]))

    pSTMT_PRINT = "print" + pEXPR + ";"
    pSTMT_PRINT.setParseAction(
        lambda result: EPrimCall(oper_print, [result[1]]))

    pSTMT_UPDATE = pNAME + "<-" + pEXPR + ";"
    pSTMT_UPDATE.setParseAction(
        lambda result: EPrimCall(oper_update, [EId(result[0]), result[2]]))

    pSTMTARR_UPDATE = pNAME + "[" + pEXPR + "]" + "<-" + pEXPR + ";"
    pSTMTARR_UPDATE.setParseAction(lambda result: EPrimCall(
        oper_update_arr, [EId(result[0]), result[5], result[2]]))

    # pSTMT_FOR = "for" + "(" + pSTMT_UPDATE + pEXPR + ";" + pSTMT_UPDATE + ")" + pSTMT
    # pSTMT_FOR.setParseAction(lambda result: EDo([result[2],EWhile(result[3], EDo([result[7],result[5]])) ] ))

    pSTMT_FOR = "for" + pSTMT_UPDATE + pEXPR + ";" + pSTMT_UPDATE + pSTMT
    pSTMT_FOR.setParseAction(lambda result: EDo(
        [result[1], EWhile(result[2], EDo([result[5], result[4]]))]))

    pSTMTS = ZeroOrMore(pSTMT)
    pSTMTS.setParseAction(lambda result: [result])

    def mkBlock(decls, stmts):
        bindings = [(n, ERefCell(expr)) for (n, expr) in decls]
        return ELet(bindings, EDo(stmts))

    pSTMT_BLOCK = "{" + pDECLS + pSTMTS + "}"
    pSTMT_BLOCK.setParseAction(lambda result: mkBlock(result[1], result[2]))

    pDEFPROC = "procedure" + pNAME + "(" + pNAMES + ")" + pSTMT
    pDEFPROC.setParseAction(
        lambda result: {
            "result":
            "procedure",
            "proc":
            (result[1], EProcedure(result[3], mkFunBody(result[3], result[5])))
        })

    pSTMT_PROC = pIDENTIFIER + "(" + pEXPRS + ")" + ";"
    pSTMT_PROC.setParseAction(lambda result: EProcCall(result[0], result[2]))

    pWITH = "(" + Keyword(
        "with") + pIDENTIFIER + pIDENTIFIER + "(" + pEXPRS + ")" + ")"
    pWITH.setParseAction(lambda result: EWith(result[2], result[3], result[5]))

    pNOTIMPLEMENTED = Keyword("<>")
    pNOTIMPLEMENTED.setParseAction(lambda result: ENotImplemented())

    pSTMT << (pSTMT_IF_1 | pSTMT_IF_2 | pSTMT_WHILE | pSTMT_PRINT | pSTMT_FOR
              | pSTMT_UPDATE | pSTMTARR_UPDATE | pSTMT_BLOCK | pSTMT_PROC
              | pWITH)

    # can't attach a parse action to pSTMT because of recursion, so let's duplicate the parser
    pTOP_STMT = pSTMT.copy()
    pTOP_STMT.setParseAction(lambda result: {
        "result": "statement",
        "stmt": result[0]
    })

    pTOP_DECL = pDECL.copy()
    pTOP_DECL.setParseAction(lambda result: {
        "result": "declaration",
        "decl": result[0]
    })

    pABSTRACT = "#abs" + pSTMT
    pABSTRACT.setParseAction(lambda result: {
        "result": "abstract",
        "stmt": result[1]
    })

    pQUIT = Keyword("#quit")
    pQUIT.setParseAction(lambda result: {"result": "quit"})

    pDEFFUN = "(" + pNAME + "(" + pNAMES + ")" + pSTMT + ")"
    pDEFFUN.setParseAction(lambda result: (result[
        1], EProcedure(result[3], mkFunBody(result[3], result[5]))))

    pDEFABSFUN = "(" + pNAME + "(" + pNAMES + ")" + pNOTIMPLEMENTED + ")"
    pDEFABSFUN.setParseAction(lambda result: (result[1], ENotImplemented()))

    pDEFFUNS = ZeroOrMore((pDEFFUN | pDEFABSFUN))
    pDEFFUNS.setParseAction(lambda result: [result])

    pTEMPLATE = Keyword(
        "class"
    ) + "(" + pNAME + pIDENTIFIER + "(" + pNAMES + ")" + "(" + pIDENTIFIERS + ")" + "(" + pDEFFUNS + ")" + ")"
    pTEMPLATE.setParseAction(
        lambda result: {
            "result":
            "template",
            "temp": (result[2],
                     ETemplate(False, result[2], result[3], result[5], result[
                         8], result[11]))
        })

    pABSTEMPLATE = Keyword(
        "absclass"
    ) + "(" + pNAME + pIDENTIFIER + "(" + pNAMES + ")" + "(" + pIDENTIFIERS + ")" + "(" + pDEFFUNS + ")" + ")"
    pABSTEMPLATE.setParseAction(
        lambda result: {
            "result":
            "template",
            "temp": (result[2],
                     ETemplate(True, result[2], result[3], result[5], result[
                         8], result[11]))
        })

    pNEWOBJ = Keyword("new") + pIDENTIFIER + "(" + pEXPRS + ")"
    pNEWOBJ.setParseAction(lambda result: EObject(result[1], result[3]))

    pOBJASS = Keyword("obj") + pIDENTIFIER + pNAME + "=" + pNEWOBJ
    pOBJASS.setParseAction(
        lambda result: {
            "result": "objectassignment",
            "assignment": (result[2], EObjectBinding(result[1], result[4]))
        })

    pMULTI = Keyword("#multi")
    pMULTI.setParseAction(lambda result: {"result": "multi"})

    pTOP = (pQUIT | pABSTRACT | pTOP_DECL | pTOP_STMT | pDEFPROC | pTEMPLATE
            | pOBJASS | pMULTI | pABSTEMPLATE)

    result = pTOP.parseString(input)[0]
    return result  # the first element of the result is the expression
Ejemplo n.º 14
0
 def create(self, pa):
     def itercalls():
         def getbrackets(blankpa, scalarpa):
             optblank = _getoptblank(blankpa, '')
             return Literal(o) + ZeroOrMore(optblank + _getarg(callchain, scalarpa, c)) + optblank + Literal(c)
         for o, c in self.bracketpairs:
             yield (Suppress(Regex("[$](?:lit|')")) + Suppress(o) + Regex("[^%s]*" % re.escape(c)) + Suppress(c)).setParseAction(Text.pa)
             yield (Suppress(Regex('[$](?:pass|[.])')) + getbrackets(Text.pa, Text.pa)).setParseAction(self._bracketspa)
             yield (Suppress('$') + self.identifier + getbrackets(Blank.pa, AnyScalar.pa)).setParseAction(_principalcallpa)
             yield (Suppress('$') + self.identifier + callchain).setParseAction(_additionalcallpa)
     optblank = _getoptblank(Blank.pa, self.boundarychars)
     callchain = Forward()
     callchain << MatchFirst(itercalls()).leaveWhitespace()
     return reduce(operator.add, [
         self.ormorecls(optblank + _getarg(callchain, self.scalarpa, self.boundarychars)),
         optblank,
         Optional(Regex("[%s]+" % re.escape(self.boundarychars)).leaveWhitespace().setParseAction(Boundary.pa) if self.boundarychars else NoMatch()),
     ]).setParseAction(pa)
Ejemplo n.º 15
0
 def __init__(self, tokens_list):
     self._markup = NoMatch()
     for token in tokens_list:
         self._markup |= token
Ejemplo n.º 16
0
 def reinit_exprs(self):
     command = reduce(lambda acc, e: acc | e[1], self.commands, NoMatch())
     self.dm_expr = self.dm_expr_head + command
     self.expr = self.expr_head + command
Ejemplo n.º 17
0
def parse_imp (input):
    # parse a string into an element of the abstract representation

    # Grammar:
    #
    # <expr> ::= <integer>
    #            true
    #            false
    #            <identifier>
    #            ( if <expr> <expr> <expr> )
    #            ( function ( <name ... ) <expr> )    
    #            ( <expr> <expr> ... )
    #
    # <decl> ::= var name = expr ; 
    #
    # <stmt> ::= if <expr> <stmt> else <stmt>
    #            while <expr> <stmt>
    #            name <- <expr> ;
    #            print <expr> ;
    #            <block>
    #
    # <block> ::= { <decl> ... <stmt> ... }
    #
    # <toplevel> ::= <decl>
    #                <stmt>
    #

    idChars = alphas+"_+*-?!=<>+"

    QUOTE = Literal('"')
    INTERNAL_QUOTE = QUOTE.copy().leaveWhitespace()

    pIDENTIFIER = Word(idChars, idChars+"0123456789")
    #### NOTE THE DIFFERENCE
    pIDENTIFIER.setParseAction(lambda result: EPrimCall(oper_deref,[EId(result[0])]))

    # A name is like an identifier but it does not return an EId...
    pNAME = Word(idChars,idChars+"0123456789") #| Keyword("&\"") | Keyword("&\'")

    pNAMECON = "," + pNAME
    pNAMECON.setParseAction(lambda result: result[1])

    pNAMES = pNAME + ZeroOrMore(pNAMECON) | ZeroOrMore(pNAME)
    pNAMES.setParseAction(lambda result: [result])

    pINTEGER = Word("0123456789")
    pINTEGER.setParseAction(lambda result: EValue(VInteger(int(result[0]))))

    QUOTE = Literal("&\"") | Literal("&\'") 
    pSTRINGSTART = Literal('"') + ZeroOrMore(Word(" ")).leaveWhitespace()
    pSTRINGSTART.setParseAction(lambda result: result[1:])

    pSTRING = pSTRINGSTART + ZeroOrMore(Combine( Word(idChars+"0123456789'"+" ") | QUOTE)) + Literal('"')
    pSTRING.setParseAction(lambda result: EValue(VString(str(result[:-1]))))

    pBOOLEAN = Keyword("true") | Keyword("false")
    pBOOLEAN.setParseAction(lambda result: EValue(VBoolean(result[0]=="true")))

    pEXPR = Forward()
    pEXPR2 = Forward()
    pSTMT_BLOCK = Forward()
    pSTMT = Forward()

    pEXPRS = ZeroOrMore(pEXPR2)
    pEXPRS.setParseAction(lambda result: [result])

    pIF = pEXPR + Keyword("?") + pEXPR + Keyword(':') + pEXPR
    pIF.setParseAction(lambda result: EIf(result[0], result[2], result[4]))


    def mkFunBody (params,body):
        bindings = [ (p,ERefCell(EId(p))) for p in params ]
        return ELet(bindings,body)

    def mkLetBody (bindings,body):
        bindings = [ (p[0],ERefCell(p[1])) for p in bindings ]
        return ELet(bindings,body)

    def multiCallHelper(result, start, i, length):
        if i < length:
            start = ECall(result[1][i][0], [result[1][i][1], start])
            multiCallHelper(result, start, i + 1, length)
        return start

    def multiCall(result):
        start = ECall(result[1][0][0], [result[0], result[1][0][1]])
        return multiCallHelper(result, start, 1, len(result[1]))

    def eFunHelper(variables, expression):
        if len(variables) == 1:
            return EFunction(variables[0], expression)
        else:
            return EFunction(variables[0], eFunHelper(variables[1:], expression))

    def eFunName(result):
        varName = result[1]
        variables = result[3]
        expression = result[-1]
        print variables, expression
        return EFunction(variables, expression, varName)

    pFUN = Keyword("fun") + "(" + pNAMES + ")" + pSTMT
    pFUN.setParseAction(lambda result: EFunction(result[2],mkFunBody(result[2],result[4])))

    pFUNR = Keyword("fun") + pNAME + "(" + pNAMES + ")" + pSTMT
    # pFUNR.setParseAction(eFunName)
    pFUNR.setParseAction(lambda result: EFunction(result[3],mkFunBody(result[3],result[5]), result[1]))

    pEXPR2CAR = "," + pEXPR2
    pEXPR2CAR.setParseAction(lambda result: result[1])

    pEXPR2MULTIALL = pEXPR2 + ZeroOrMore(pEXPR2CAR) | ZeroOrMore(pEXPR2)
    pEXPR2MULTIALL.setParseAction(lambda result: [result])

    pFUNCALL = pEXPR + "(" + pEXPR2MULTIALL + ")"
    pFUNCALL.setParseAction(lambda result: ECall(result[0], result[2]))

    pBINDINGCAR = "," + pNAME + "=" + pEXPR2
    pBINDINGCAR.setParseAction(lambda result: (result[1], result[3]))
    
    pBINDINGCON = pNAME + "=" + pEXPR2
    pBINDINGCON.setParseAction(lambda result: (result[0], result[2]))

    pBINDINGS = pBINDINGCON  + ZeroOrMore(pBINDINGCAR)
    pBINDINGS.setParseAction(lambda result: [result])

    pLET = Keyword("let") + "(" + pBINDINGS + ")" + pEXPR2
    pLET.setParseAction(lambda result: mkLetBody(result[2], result[4]))

    pCALLG = pIDENTIFIER + pEXPR2
    pCALLG.setParseAction(lambda result: (result[0], result[1]))

    pCALL1S = OneOrMore(pCALLG)
    pCALL1S.setParseAction(lambda result: [ result ])

    pCALL =  pEXPR + pCALL1S 
    pCALL.setParseAction(multiCall)

    pCALL1 = pIDENTIFIER + pEXPR2
    pCALL1.setParseAction(lambda result: ECall(result[0], [result[1]]))

    pNOT = "not" + pEXPR2
    pNOT.setParseAction(lambda result: EPrimCall(oper_not, [result[1]]))

    pARRAYITEM = "," + pEXPR2
    pARRAYITEM.setParseAction(lambda result: (result[1]))

    pARRAYITEMS = ZeroOrMore(pARRAYITEM)
    pARRAYITEMS.setParseAction(lambda result: [result])

    pARRAY = "[" + ZeroOrMore(pEXPR2) + pARRAYITEMS + "]"
    pARRAY.setParseAction(lambda result: EArray(result[1],result[2]))

    pDICTPAIR = pNAME + ":" + pEXPR
    pDICTPAIR.setParseAction(lambda result: (result[0],result[2]))

    pDICTPAIRWITHCOMMA = "," + pNAME + ":" + pEXPR
    pDICTPAIRWITHCOMMA.setParseAction(lambda result: (result[1],result[3]))

    pDICTS = ZeroOrMore(pDICTPAIRWITHCOMMA)
    pDICTS.setParseAction(lambda result: [ result ])

    pDICT = "{" + pDICTPAIR + pDICTS + "}"
    pDICT.setParseAction(lambda result:EDict(result[1],result[2]))

    pEXPR2P = "(" + pEXPR2 + ")"
    pEXPR2P.setParseAction(lambda result: result[1])

    pACCESS = pNAME + "[" + pEXPR + "]"
    pACCESS.setParseAction(lambda result: EPrimCall(oper_access_arr,[EId(result[0]),result[2]]))

    pLEN = Keyword("len") + "(" + pNAME + ")"
    pLEN.setParseAction(lambda result: EPrimCall(oper_len,[EId(result[2])]))

    pEXPR << ( pEXPR2P |  pINTEGER | pNOT | pARRAY | pACCESS | pDICT | pSTRING | pBOOLEAN | pIDENTIFIER | pCALL1 | pLEN )

    pEXPR2 << ( pLET | pFUN | pFUNR | pFUNCALL | pIF | pCALL | pEXPR )

    pDECL_VAR_E = "var" + pNAME + ";"
    pDECL_VAR_E.setParseAction(lambda result: (result[1], EValue(VNone)))

    pDECL_VAR = "var" + pNAME + "=" + pEXPR2 + ";"
    pDECL_VAR.setParseAction(lambda result: (result[1],result[3]))

    pDECL_PROCEDURE = "def" + pNAME + "(" + pNAMES + ")" + pSTMT
    pDECL_PROCEDURE.setParseAction(lambda result: (result[1], EProcedure(result[3], mkFunBody(result[3], result[5]))))

    # hack to get pDECL to match only PDECL_VAR (but still leave room
    # to add to pDECL later)
    pDECL = ( pDECL_VAR_E | pDECL_VAR | pDECL_PROCEDURE | NoMatch() | ";" )

    pDECLS = ZeroOrMore(pDECL)
    pDECLS.setParseAction(lambda result: [result])

    pSTMT_IF_1 = "if (" + pEXPR2 + ")" + pSTMT + "else" + pSTMT
    pSTMT_IF_1.setParseAction(lambda result: EIf(result[1],result[3],result[5]))

    pSTMT_IF_2 = "if (" + pEXPR2 + ")" + pSTMT
    pSTMT_IF_2.setParseAction(lambda result: EIf(result[1],result[3],EValue(VBoolean(True))))
   
    pSTMT_WHILE = "while (" + pEXPR2 + ")" + pSTMT
    pSTMT_WHILE.setParseAction(lambda result: EWhile(result[1],result[3]))

    pSTMT_FOR = "for (" + pNAME + "in" + pEXPR2 + ")" + pSTMT
    pSTMT_FOR.setParseAction(lambda result: EFor(result[1], result[3], result[5]))

    pSTMT_PRINT_STMS = "," + pEXPR2
    pSTMT_PRINT_STMS.setParseAction(lambda result: [ result[1] ])

    pSTMT_PRINT_ZERO = ZeroOrMore(pSTMT_PRINT_STMS)
    pSTMT_PRINT_ZERO.setParseAction(lambda result: [ result ])

    def printStmEval(result):
        newArray = []
        newArray.append(result[1])
        for i in result[2]:
            newArray.append(i)
        return EPrimCall(oper_print,newArray)

    pSTMT_PRINT = "print" + pEXPR2 + pSTMT_PRINT_ZERO + ";"
    pSTMT_PRINT.setParseAction(printStmEval)

    pSTMT_UPDATE_ARR = pNAME + "[" + pEXPR +"]" + "=" + pEXPR + ";"
    pSTMT_UPDATE_ARR.setParseAction(lambda result: EPrimCall(oper_update_arr,[EId(result[0]),result[2],result[5]]))

    pSTMT_UPDATE = pNAME + "=" + pEXPR2 + ";"
    pSTMT_UPDATE.setParseAction(lambda result: EPrimCall(oper_update,[EId(result[0]),result[2]]))

    pSTMTS = ZeroOrMore(pSTMT)
    pSTMTS.setParseAction(lambda result: [result])

    def mkBlock (decls,stmts):
        bindings = [ (n,ERefCell(expr)) for (n,expr) in decls ]
        return ELet(bindings,EDo(stmts))
        
    pSTMT_BLOCK = "{" + pDECLS + pSTMTS + "}"
    pSTMT_BLOCK.setParseAction(lambda result: mkBlock(result[1],result[2]))

    pSTMT_pEXPR2 = pEXPR2 + ";"
    pSTMT_pEXPR2.setParseAction(lambda result: result[0])

    pSTMT << ( pSTMT_IF_1 | pSTMT_IF_2 | pSTMT_WHILE | pSTMT_FOR | pSTMT_PRINT | pSTMT_UPDATE_ARR | pSTMT_UPDATE | pSTMT_BLOCK | pSTMT_pEXPR2 | pEXPR2 )

    # can't attach a parse action to pSTMT because of recursion, so let's duplicate the parser
    pTOP_STMT = pSTMT.copy()
    pTOP_STMT.setParseAction(lambda result: {"result":"statement",
                                             "stmt":result[0]})

    pTOP_DECL = pDECL.copy()
    pTOP_DECL.setParseAction(lambda result: {"result":"declaration",
                                             "decl":result[0]})

    pABSTRACT = "#abs" + pSTMT
    pABSTRACT.setParseAction(lambda result: {"result":"abstract",
                                             "stmt":result[1]})
    pQUIT = Keyword("#quit")
    pQUIT.setParseAction(lambda result: {"result":"quit"})

    pTOP =  ZeroOrMore(pTOP_DECL) + ZeroOrMore(pTOP_STMT) 
    return pTOP.parseString(input)
Ejemplo n.º 18
0
 def reinit_exprs(self):
     """Combines all expressions into a single expression which can be used to match commands."""
     command = reduce(lambda acc, e: acc | e[1], self.commands, NoMatch())
     self.dm_expr = self.dm_expr_head + command
     self.expr = self.expr_head + command
Ejemplo n.º 19
0
def evaluator(variables, functions, string, cs=False):
    '''
    Evaluate an expression. Variables are passed as a dictionary
    from string to value. Unary functions are passed as a dictionary
    from string to function. Variables must be floats.
    cs: Case sensitive

    TODO: Fix it so we can pass integers and complex numbers in variables dict
    '''
    # log.debug("variables: {0}".format(variables))
    # log.debug("functions: {0}".format(functions))
    # log.debug("string: {0}".format(string))

    def lower_dict(d):
        return dict([(k.lower(), d[k]) for k in d])

    all_variables = copy.copy(default_variables)
    all_functions = copy.copy(default_functions)

    if not cs:
        all_variables = lower_dict(all_variables)
        all_functions = lower_dict(all_functions)

    all_variables.update(variables)
    all_functions.update(functions)

    if not cs:
        string_cs = string.lower()
        all_functions = lower_dict(all_functions)
        all_variables = lower_dict(all_variables)
        CasedLiteral = CaselessLiteral
    else:
        string_cs = string
        CasedLiteral = Literal

    check_variables(string_cs, set(
        all_variables.keys() + all_functions.keys()))

    if string.strip() == "":
        return float('nan')

    ops = {"^": operator.pow,
           "*": operator.mul,
           "/": operator.truediv,
           "+": operator.add,
           "-": operator.sub,
           }
    # We eliminated extreme ones, since they're rarely used, and potentially
    # confusing. They may also conflict with variables if we ever allow e.g.
    # 5R instead of 5*R
    suffixes = {'%': 0.01, 'k': 1e3, 'M': 1e6, 'G': 1e9,
                'T': 1e12,  # 'P':1e15,'E':1e18,'Z':1e21,'Y':1e24,
                'c': 1e-2, 'm': 1e-3, 'u': 1e-6,
                'n': 1e-9, 'p': 1e-12}  # ,'f':1e-15,'a':1e-18,'z':1e-21,'y':1e-24}

    def super_float(text):
        ''' Like float, but with si extensions. 1k goes to 1000'''
        if text[-1] in suffixes:
            return float(text[:-1]) * suffixes[text[-1]]
        else:
            return float(text)

    def number_parse_action(x):  # [ '7' ] ->  [ 7 ]
        return [super_float("".join(x))]

    def exp_parse_action(x):  # [ 2 ^ 3 ^ 2 ] -> 512
        x = [e for e in x if isinstance(e, numbers.Number)]  # Ignore ^
        x.reverse()
        x = reduce(lambda a, b: b ** a, x)
        return x

    def parallel(x):  # Parallel resistors [ 1 2 ] => 2/3
        # convert from pyparsing.ParseResults, which doesn't support '0 in x'
        x = list(x)
        if len(x) == 1:
            return x[0]
        if 0 in x:
            return float('nan')
        x = [1. / e for e in x if isinstance(e, numbers.Number)]  # Ignore ||
        return 1. / sum(x)

    def sum_parse_action(x):  # [ 1 + 2 - 3 ] -> 0
        total = 0.0
        op = ops['+']
        for e in x:
            if e in set('+-'):
                op = ops[e]
            else:
                total = op(total, e)
        return total

    def prod_parse_action(x):  # [ 1 * 2 / 3 ] => 0.66
        prod = 1.0
        op = ops['*']
        for e in x:
            if e in set('*/'):
                op = ops[e]
            else:
                prod = op(prod, e)
        return prod

    def func_parse_action(x):
        return [all_functions[x[0]](x[1])]

    # SI suffixes and percent
    number_suffix = reduce(lambda a, b: a | b, map(
        Literal, suffixes.keys()), NoMatch())
    (dot, minus, plus, times, div, lpar, rpar, exp) = map(Literal, ".-+*/()^")

    number_part = Word(nums)

    # 0.33 or 7 or .34 or 16.
    inner_number = (number_part + Optional(
        "." + Optional(number_part))) | ("." + number_part)

    # 0.33k or -17
    number = (Optional(minus | plus) + inner_number
              + Optional(CaselessLiteral("E") + Optional(
                  (plus | minus)) + number_part)
              + Optional(number_suffix))
    number = number.setParseAction(number_parse_action)  # Convert to number

    # Predefine recursive variables
    expr = Forward()
    factor = Forward()

    def sreduce(f, l):
        ''' Same as reduce, but handle len 1 and len 0 lists sensibly '''
        if len(l) == 0:
            return NoMatch()
        if len(l) == 1:
            return l[0]
        return reduce(f, l)

    # Handle variables passed in. E.g. if we have {'R':0.5}, we make the substitution.
    # Special case for no variables because of how we understand PyParsing is
    # put together
    if len(all_variables) > 0:
        # We sort the list so that var names (like "e2") match before
        # mathematical constants (like "e"). This is kind of a hack.
        all_variables_keys = sorted(
            all_variables.keys(), key=len, reverse=True)
        varnames = sreduce(lambda x, y: x | y, map(
            lambda x: CasedLiteral(x), all_variables_keys))
        varnames.setParseAction(lambda x: map(lambda y: all_variables[y], x))
    else:
        varnames = NoMatch()

    # Same thing for functions.
    if len(all_functions) > 0:
        funcnames = sreduce(lambda x, y: x | y,
                            map(lambda x: CasedLiteral(x), all_functions.keys()))
        function = funcnames + lpar.suppress() + expr + rpar.suppress()
        function.setParseAction(func_parse_action)
    else:
        function = NoMatch()

    atom = number | function | varnames | lpar + expr + rpar
    factor << (atom + ZeroOrMore(
        exp + atom)).setParseAction(exp_parse_action)  # 7^6
    paritem = factor + ZeroOrMore(Literal('||') + factor)  # 5k || 4k
    paritem = paritem.setParseAction(parallel)
    term = paritem + ZeroOrMore((times | div) + paritem)  # 7 * 5 / 4 - 3
    term = term.setParseAction(prod_parse_action)
    expr << Optional((plus | minus)) + term + ZeroOrMore(
        (plus | minus) + term)  # -5 + 4 - 3
    expr = expr.setParseAction(sum_parse_action)
    return (expr + stringEnd).parseString(string)[0]
Ejemplo n.º 20
0
def parse_imp(input):
    # parse a string into an element of the abstract representation

    # Grammar:
    #
    # <expr> ::= <integer>
    #            true
    #            false
    #            <identifier>
    #            ( if <expr> <expr> <expr> )
    #            ( function ( <name ... ) <expr> )
    #            ( <expr> <expr> ... )
    #
    # <decl> ::= var name = expr ;
    #
    # <stmt> ::= if <expr> <stmt> else <stmt>
    #            while <expr> <stmt>
    #            name <- <expr> ;
    #            print <expr> ;
    #            <block>
    #
    # <block> ::= { <decl> ... <stmt> ... }
    #
    # <toplevel> ::= <decl>
    #                <stmt>
    #

    idChars = alphas + "_+*-?!=<>+"

    QUOTE = Literal('"')
    INTERNAL_QUOTE = QUOTE.copy().leaveWhitespace()

    pIDENTIFIER = Word(idChars, idChars + "0123456789")
    #### NOTE THE DIFFERENCE
    pIDENTIFIER.setParseAction(
        lambda result: EPrimCall(oper_deref, [EId(result[0])]))

    # A name is like an identifier but it does not return an EId...
    pNAME = Word(idChars,
                 idChars + "0123456789")  #| Keyword("&\"") | Keyword("&\'")

    pNAMES = ZeroOrMore(pNAME)
    pNAMES.setParseAction(lambda result: [result])

    pINTEGER = Word("0123456789")
    pINTEGER.setParseAction(lambda result: EValue(VInteger(int(result[0]))))

    QUOTE = Literal("&\"") | Literal("&\'")
    pSTRING = Literal('"') + ZeroOrMore(
        Combine(Word(idChars + "0123456789'" + " ") | QUOTE)) + Literal('"')
    pSTRING.setParseAction(lambda result: EValue(VString(str(result[1:-1]))))

    pBOOLEAN = Keyword("true") | Keyword("false")
    pBOOLEAN.setParseAction(
        lambda result: EValue(VBoolean(result[0] == "true")))

    pEXPR = Forward()

    pEXPRS = ZeroOrMore(pEXPR)
    pEXPRS.setParseAction(lambda result: [result])

    pIF = "(" + Keyword("if") + pEXPR + pEXPR + pEXPR + ")"
    pIF.setParseAction(lambda result: EIf(result[2], result[3], result[4]))

    def mkFunBody(params, body):
        bindings = [(p, ERefCell(EId(p))) for p in params]
        return ELet(bindings, body)

    def letToFun(result):
        func = result[5]
        binds = result[3]
        params = []
        vals = []
        for p, v in binds:
            params.append(p)
            vals.append(v)
        return ECall(EFunction(params, func), vals)

    pFUN = "(" + Keyword("function") + "(" + pNAMES + ")" + pEXPR + ")"
    pFUN.setParseAction(
        lambda result: EFunction(result[3], mkFunBody(result[3], result[5])))

    pBINDING = "(" + pNAME + pEXPR + ")"
    pBINDING.setParseAction(lambda result: (result[1], result[2]))

    pBINDINGS = OneOrMore(pBINDING)
    pBINDINGS.setParseAction(lambda result: [result])

    pLET = "(" + Keyword("let") + "(" + pBINDINGS + ")" + pEXPR + ")"
    pLET.setParseAction(letToFun)

    pCALL = "(" + pEXPR + pEXPRS + ")"
    pCALL.setParseAction(lambda result: ECall(result[1], result[2]))

    pARRAY = "(" + Keyword("new-array") + pEXPR + ")"
    pARRAY.setParseAction(lambda result: EArray(result[2]))

    pINDEX = Keyword("index") + pINTEGER
    pCALL.setParseAction(lambda result: ECall(result[1], result[2]))

    pWITH = "(" + Keyword("with") + pEXPR + pEXPR + ")"
    pWITH.setParseAction(lambda result: EWithObj(result[2], result[3]))

    pEXPR << (pINTEGER | pARRAY | pSTRING | pWITH | pBOOLEAN | pIDENTIFIER
              | pIF | pLET | pFUN | pCALL)

    pDECL_VAR = "var" + pNAME + "=" + pEXPR + ";"
    pDECL_VAR.setParseAction(lambda result: (result[1], result[3]))

    pSTMT = Forward()

    pDECL_PROCEDURE = "procedure" + pNAME + "(" + pNAMES + ")" + pSTMT
    pDECL_PROCEDURE.setParseAction(lambda result: (result[
        1], EProcedure(result[3], mkFunBody(result[3], result[5]))))

    # hack to get pDECL to match only PDECL_VAR (but still leave room
    # to add to pDECL later)
    pDECL = (pDECL_VAR | pDECL_PROCEDURE | NoMatch() | ";")

    pDECLS = ZeroOrMore(pDECL)
    pDECLS.setParseAction(lambda result: [result])

    pSTMT_IF_1 = "if" + pEXPR + pSTMT + "else" + pSTMT
    pSTMT_IF_1.setParseAction(
        lambda result: EIf(result[1], result[2], result[4]))

    pSTMT_IF_2 = "if" + pEXPR + pSTMT
    pSTMT_IF_2.setParseAction(
        lambda result: EIf(result[1], result[2], EValue(VBoolean(True))))

    pSTMT_WHILE = "while" + pEXPR + pSTMT
    pSTMT_WHILE.setParseAction(lambda result: EWhile(result[1], result[2]))

    pSTMT_FOR = "for" + pDECLS + pEXPR + ";" + pSTMT + pSTMT
    pSTMT_FOR.setParseAction(
        lambda result: EFor(result[1], result[2], result[4], result[5]))

    pSTMT_PRINT = "print" + pEXPR + ";"
    pSTMT_PRINT.setParseAction(
        lambda result: EPrimCall(oper_print, [result[1]]))

    pSTMT_UPDATE_ARR = pNAME + "[" + pINTEGER + "]" + "<-" + pEXPR + ";"
    pSTMT_UPDATE_ARR.setParseAction(lambda result: EPrimCall(
        oper_update_arr, [EId(result[0]), result[2], result[5]]))

    pSTMT_UPDATE = pNAME + "<-" + pEXPR + ";"
    pSTMT_UPDATE.setParseAction(
        lambda result: EPrimCall(oper_update, [EId(result[0]), result[2]]))

    pSTMT_PROCEDURE = pEXPR + "(" + pEXPRS + ")" + ";"
    pSTMT_PROCEDURE.setParseAction(lambda result: ECall(result[0], result[2]))

    pSTMTS = ZeroOrMore(pSTMT)
    pSTMTS.setParseAction(lambda result: [result])

    def mkBlock(decls, stmts):
        bindings = [(n, ERefCell(expr)) for (n, expr) in decls]
        return ELet(bindings, EDo(stmts))

    pSTMT_BLOCK = "{" + pDECLS + pSTMTS + "}"
    pSTMT_BLOCK.setParseAction(lambda result: mkBlock(result[1], result[2]))

    pSTMT << (pSTMT_IF_1 | pSTMT_IF_2 | pWITH | pSTMT_WHILE | pSTMT_FOR
              | pSTMT_PRINT | pSTMT_UPDATE_ARR | pSTMT_UPDATE | pSTMT_PROCEDURE
              | pSTMT_BLOCK)

    # can't attach a parse action to pSTMT because of recursion, so let's duplicate the parser
    pTOP_STMT = pSTMT.copy()
    pTOP_STMT.setParseAction(lambda result: {
        "result": "statement",
        "stmt": result[0]
    })

    pTOP_DECL = pDECL.copy()
    pTOP_DECL.setParseAction(lambda result: {
        "result": "declaration",
        "decl": result[0]
    })

    pABSTRACT = "#abs" + pSTMT
    pABSTRACT.setParseAction(lambda result: {
        "result": "abstract",
        "stmt": result[1]
    })
    pQUIT = Keyword("#quit")
    pQUIT.setParseAction(lambda result: {"result": "quit"})

    pTOP = (pQUIT | pABSTRACT | pTOP_DECL | pTOP_STMT)

    result = pTOP.parseString(input)[0]
    return result  # the first element of the result is the expression
Ejemplo n.º 21
0
def create_parser(regexes,
                  pattern_matchers,
                  range_fillers,
                  quote_pairs=[('\'', '\''), ('"', '"')],
                  delimiters=[','],
                  require_quotes=False,
                  require_delimiter=False,
                  allow_empty=True):
    if isinstance(regexes, string_types) or isinstance(regexes,
                                                       re._pattern_type):
        regexes = [regexes]
        pattern_matchers = [pattern_matchers]
        range_fillers = [range_fillers]
    assert len(regexes) == len(pattern_matchers)
    assert len(regexes) == len(range_fillers)

    code_patterns = list(
        starmap(
            lambda regex, pattern_matcher: Regex(regex).setParseAction(
                lambda s, loc, toks: frozenset(pattern_matcher(toks[0]))),
            zip(regexes, pattern_matchers)))
    if require_quotes:
        quoted_code_patterns = [NoMatch() for _ in code_patterns]
    else:
        quoted_code_patterns = code_patterns
    for opener, closer in quote_pairs:
        quoted_code_patterns = list(
            starmap(
                lambda quoted_code_pattern, code_pattern: quoted_code_pattern |
                (Literal(opener).suppress() + code_pattern + Literal(closer).
                 suppress()), zip(quoted_code_patterns, code_patterns)))

    code_ranges = map(
        lambda quoted_code_pattern: quoted_code_pattern + Literal('-').
        suppress() + quoted_code_pattern, quoted_code_patterns)
    code_ranges = list(
        starmap(
            lambda code_range, range_filler: code_range.
            setParseAction(lambda s, loc, toks: frozenset(
                range_filler(toks[0], toks[1]))),
            zip(code_ranges, range_fillers)))

    quoted_code_ranges = [NoMatch() for _ in code_ranges]
    for opener, closer in quote_pairs:
        quoted_code_ranges = list(
            starmap(
                lambda quoted_code_range, code_pattern: quoted_code_range |
                (Literal(opener).suppress() + code_pattern + Literal('-').
                 suppress() + code_pattern + Literal(closer).suppress()),
                zip(quoted_code_ranges, code_patterns)))
    quoted_code_ranges = list(
        starmap(
            lambda quoted_code_range, range_filler: quoted_code_range.
            setParseAction(lambda s, loc, toks: frozenset(
                range_filler(toks[0], toks[1]))),
            zip(quoted_code_ranges, range_fillers)))
    any_code_ranges = list(starmap(or_, zip(quoted_code_ranges, code_ranges)))
    quoted_code_pattern = reduce(xor, quoted_code_patterns)
    any_code_range = reduce(xor, any_code_ranges)
    any_delim = reduce(xor, map(Literal, delimiters))
    if allow_empty:
        any_delim = OneOrMore(any_delim)
    code_list_continuation = any_delim.suppress() + (any_code_range
                                                     | quoted_code_pattern)
    if not require_delimiter:
        code_list_continuation |= White().suppress() + (any_code_range
                                                        | quoted_code_pattern)
    code_list = (any_code_range | quoted_code_pattern) + ZeroOrMore(
        code_list_continuation) + Optional(
            reduce(or_, map(Literal, delimiters))).suppress() + StringEnd()
    return code_list
Ejemplo n.º 22
0
def parse_imp(input):
    # parse a string into an element of the abstract representation

    # Grammar:
    #
    # <expr> ::= <integer>
    #            true
    #            false
    #            <identifier>
    #            ( if <expr> <expr> <expr> )
    #            ( function ( <name ... ) <expr> )
    #            ( <expr> <expr> ... )
    #
    # <decl> ::= var name = expr ;
    #
    # <stmt> ::= if <expr> <stmt> else <stmt>
    #            while <expr> <stmt>
    #            name <- <expr> ;
    #            print <expr> ;
    #            <expr> ;
    #            <block>
    #
    # <block> ::= { <decl> ... <stmt> ... }
    #
    # <toplevel> ::= <decl>
    #                <stmt>
    #

    idChars = alphas + "_+*-?!=<>"

    pIDENTIFIER = Word(idChars, idChars + "0123456789")
    #### NOTE THE DIFFERENCE
    pIDENTIFIER.setParseAction(
        lambda result: EPrimCall(oper_deref, [EId(result[0])]))

    # A name is like an identifier but it does not return an EId...
    pNAME = Word(idChars, idChars + "0123456789")

    pNAMES = ZeroOrMore(pNAME)
    pNAMES.setParseAction(lambda result: [result])

    pINTEGER = Word("0123456789")
    pINTEGER.setParseAction(lambda result: EValue(VInteger(int(result[0]))))

    pBOOLEAN = Keyword("true") | Keyword("false")
    pBOOLEAN.setParseAction(
        lambda result: EValue(VBoolean(result[0] == "true")))

    pEXPR = Forward()

    pEXPRS = ZeroOrMore(pEXPR)
    pEXPRS.setParseAction(lambda result: [result])

    pIF = "(" + Keyword("if") + pEXPR + pEXPR + pEXPR + ")"
    pIF.setParseAction(lambda result: EIf(result[2], result[3], result[4]))

    def mkFunBody(params, body):
        bindings = [(p, ERefCell(EId(p))) for p in params]
        return ELet(bindings, body)

    pFUN = "(" + Keyword("function") + "(" + pNAMES + ")" + pEXPR + ")"
    pFUN.setParseAction(
        lambda result: EFunction(result[3], mkFunBody(result[3], result[5])))

    pCALL = "(" + pEXPR + pEXPRS + ")"
    pCALL.setParseAction(lambda result: ECall(result[1], result[2]))

    pEXPR << (pINTEGER | pBOOLEAN | pIDENTIFIER | pIF | pFUN | pCALL)

    pDECL_VAR = "var" + pNAME + "=" + pEXPR + ";"
    pDECL_VAR.setParseAction(lambda result: (result[1], result[3]))

    # hack to get pDECL to match only PDECL_VAR (but still leave room
    # to add to pDECL later)
    pDECL = (pDECL_VAR | NoMatch())

    pDECLS = ZeroOrMore(pDECL)
    pDECLS.setParseAction(lambda result: [result])

    pSTMT = Forward()

    pSTMT_IF_1 = "if" + pEXPR + pSTMT + "else" + pSTMT
    pSTMT_IF_1.setParseAction(
        lambda result: EIf(result[1], result[2], result[4]))

    pSTMT_IF_2 = "if" + pEXPR + pSTMT
    pSTMT_IF_2.setParseAction(
        lambda result: EIf(result[1], result[2], EValue(VBoolean(True))))

    pSTMT_WHILE = "while" + pEXPR + pSTMT
    pSTMT_WHILE.setParseAction(lambda result: EWhile(result[1], result[2]))

    pSTMT_PRINT = "print" + pEXPR + ";"
    pSTMT_PRINT.setParseAction(
        lambda result: EPrimCall(oper_print, [result[1]]))

    pSTMT_UPDATE = pNAME + "<-" + pEXPR + ";"
    pSTMT_UPDATE.setParseAction(
        lambda result: EPrimCall(oper_update, [EId(result[0]), result[2]]))

    pSTMT_EXPR = pEXPR + ";"
    pSTMT_EXPR.setParseAction(lambda result: result[0])

    pSTMTS = ZeroOrMore(pSTMT)
    pSTMTS.setParseAction(lambda result: [result])

    def mkBlock(decls, stmts):
        bindings = [(n, ERefCell(expr)) for (n, expr) in decls]
        return ELet(bindings, EDo(stmts))

    pSTMT_BLOCK = "{" + pDECLS + pSTMTS + "}"
    pSTMT_BLOCK.setParseAction(lambda result: mkBlock(result[1], result[2]))

    pSTMT << (pSTMT_IF_1 | pSTMT_IF_2 | pSTMT_WHILE | pSTMT_PRINT
              | pSTMT_UPDATE | pSTMT_EXPR | pSTMT_BLOCK)

    # can't attach a parse action to pSTMT because of recursion, so let's duplicate the parser
    pTOP_STMT = pSTMT.copy()
    pTOP_STMT.setParseAction(lambda result: {
        "result": "statement",
        "stmt": result[0]
    })

    pTOP_DECL = pDECL.copy()
    pTOP_DECL.setParseAction(lambda result: {
        "result": "declaration",
        "decl": result[0]
    })

    pABSTRACT = "#abs" + pSTMT
    pABSTRACT.setParseAction(lambda result: {
        "result": "abstract",
        "stmt": result[1]
    })

    pQUIT = Keyword("#quit")
    pQUIT.setParseAction(lambda result: {"result": "quit"})

    pTOP = (pQUIT | pABSTRACT | pTOP_DECL | pTOP_STMT)

    result = pTOP.parseString(input)[0]
    return result  # the first element of the result is the expression