Ejemplo n.º 1
0
def parsedepfile(pathname):
    """
    Parse a filename listing only depencencies into a parserdata.StatementList.
    """
    def continuation_iter(lines):
        current_line = []
        for line in lines:
            line = line.rstrip()
            if line.endswith("\\"):
                current_line.append(line.rstrip("\\"))
                continue
            if not len(line):
                continue
            current_line.append(line)
            yield ''.join(current_line)
            current_line = []
        if current_line:
            yield ''.join(current_line)

    pathname = os.path.realpath(pathname)
    stmts = parserdata.StatementList()
    for line in continuation_iter(open(pathname).readlines()):
        target, deps = line.split(":", 1)
        stmts.append(
            parserdata.Rule(data.StringExpansion(target, None),
                            data.StringExpansion(deps, None), False))
    return stmts
Ejemplo n.º 2
0
def parsedepfile(pathname):
    """
    Parse a filename listing only depencencies into a parserdata.StatementList.
    Simple variable references are allowed in such files.
    """
    def continuation_iter(lines):
        current_line = []
        for line in lines:
            line = line.rstrip()
            if line.endswith("\\"):
                current_line.append(line.rstrip("\\"))
                continue
            if not len(line):
                continue
            current_line.append(line)
            yield ''.join(current_line)
            current_line = []
        if current_line:
            yield ''.join(current_line)

    def get_expansion(s):
        if '$' in s:
            expansion = data.Expansion()
            # for an input like e.g. "foo $(bar) baz",
            # _vars.split returns ["foo", "bar", "baz"]
            # every other element is a variable name.
            for i, element in enumerate(_vars.split(s)):
                if i % 2:
                    expansion.appendfunc(
                        functions.VariableRef(
                            None, data.StringExpansion(element, None)))
                elif element:
                    expansion.appendstr(element)

            return expansion

        return data.StringExpansion(s, None)

    pathname = os.path.realpath(pathname)
    stmts = parserdata.StatementList()
    for line in continuation_iter(open(pathname).readlines()):
        target, deps = _depfilesplitter.split(line, 1)
        stmts.append(
            parserdata.Rule(get_expansion(target), get_expansion(deps), False))
    return stmts
Ejemplo n.º 3
0
def parsestring(s, filename):
    """
    Parse a string containing makefile data into a parserdata.StatementList.
    """

    currule = False
    condstack = [parserdata.StatementList()]

    fdlines = enumeratelines(s, filename)
    for d in fdlines:
        assert len(condstack) > 0

        offset = d.lstart

        if currule and offset < d.lend and d.s[offset] == '\t':
            e, token, offset = parsemakesyntax(d, offset + 1, (),
                                               itercommandchars)
            assert token is None
            assert offset is None
            condstack[-1].append(parserdata.Command(e))
            continue

        # To parse Makefile syntax, we first strip leading whitespace and
        # look for initial keywords. If there are no keywords, it's either
        # setting a variable or writing a rule.

        offset = d.skipwhitespace(offset)
        if offset is None:
            continue

        m = _directivesre.match(d.s, offset, d.lend)
        if m is not None:
            kword = m.group(1)
            offset = m.end(0)

            if kword == 'endif':
                _ensureend(d, offset,
                           "Unexpected data after 'endif' directive")
                if len(condstack) == 1:
                    raise SyntaxError("unmatched 'endif' directive",
                                      d.getloc(offset))

                condstack.pop().endloc = d.getloc(offset)
                continue

            if kword == 'else':
                if len(condstack) == 1:
                    raise SyntaxError("unmatched 'else' directive",
                                      d.getloc(offset))

                m = _conditionre.match(d.s, offset, d.lend)
                if m is None:
                    _ensureend(d, offset,
                               "Unexpected data after 'else' directive.")
                    condstack[-1].addcondition(d.getloc(offset),
                                               parserdata.ElseCondition())
                else:
                    kword = m.group(1)
                    if kword not in _conditionkeywords:
                        raise SyntaxError(
                            "Unexpected condition after 'else' directive.",
                            d.getloc(offset))

                    startoffset = offset
                    offset = d.skipwhitespace(m.end(1))
                    c = _conditionkeywords[kword](d, offset)
                    condstack[-1].addcondition(d.getloc(startoffset), c)
                continue

            if kword in _conditionkeywords:
                c = _conditionkeywords[kword](d, offset)
                cb = parserdata.ConditionBlock(d.getloc(d.lstart), c)
                condstack[-1].append(cb)
                condstack.append(cb)
                continue

            if kword == 'endef':
                raise SyntaxError("endef without matching define",
                                  d.getloc(offset))

            if kword == 'define':
                currule = False
                vname, t, i = parsemakesyntax(d, offset, (), itermakefilechars)
                vname.rstrip()

                startloc = d.getloc(d.lstart)
                value = iterdefinelines(fdlines, startloc)
                condstack[-1].append(
                    parserdata.SetVariable(vname,
                                           value=value,
                                           valueloc=startloc,
                                           token='=',
                                           targetexp=None))
                continue

            if kword in ('include', '-include', 'includedeps', '-includedeps'):
                if kword.startswith('-'):
                    required = False
                    kword = kword[1:]
                else:
                    required = True

                deps = kword == 'includedeps'

                currule = False
                incfile, t, offset = parsemakesyntax(d, offset, (),
                                                     itermakefilechars)
                condstack[-1].append(
                    parserdata.Include(incfile, required, deps))

                continue

            if kword == 'vpath':
                currule = False
                e, t, offset = parsemakesyntax(d, offset, (),
                                               itermakefilechars)
                condstack[-1].append(parserdata.VPathDirective(e))
                continue

            if kword == 'override':
                currule = False
                vname, token, offset = parsemakesyntax(d, offset,
                                                       _varsettokens,
                                                       itermakefilechars)
                vname.lstrip()
                vname.rstrip()

                if token is None:
                    raise SyntaxError("Malformed override directive, need =",
                                      d.getloc(d.lstart))

                value = flattenmakesyntax(d, offset).lstrip()

                condstack[-1].append(
                    parserdata.SetVariable(
                        vname,
                        value=value,
                        valueloc=d.getloc(offset),
                        token=token,
                        targetexp=None,
                        source=data.Variables.SOURCE_OVERRIDE))
                continue

            if kword == 'export':
                currule = False
                e, token, offset = parsemakesyntax(d, offset, _varsettokens,
                                                   itermakefilechars)
                e.lstrip()
                e.rstrip()

                if token is None:
                    condstack[-1].append(
                        parserdata.ExportDirective(e, concurrent_set=False))
                else:
                    condstack[-1].append(
                        parserdata.ExportDirective(e, concurrent_set=True))

                    value = flattenmakesyntax(d, offset).lstrip()
                    condstack[-1].append(
                        parserdata.SetVariable(e,
                                               value=value,
                                               valueloc=d.getloc(offset),
                                               token=token,
                                               targetexp=None))

                continue

            if kword == 'unexport':
                e, token, offset = parsemakesyntax(d, offset, (),
                                                   itermakefilechars)
                condstack[-1].append(parserdata.UnexportDirective(e))
                continue

        e, token, offset = parsemakesyntax(d, offset,
                                           _varsettokens + ('::', ':'),
                                           itermakefilechars)
        if token is None:
            e.rstrip()
            e.lstrip()
            if not e.isempty():
                condstack[-1].append(parserdata.EmptyDirective(e))
            continue

        # if we encountered real makefile syntax, the current rule is over
        currule = False

        if token in _varsettokens:
            e.lstrip()
            e.rstrip()

            value = flattenmakesyntax(d, offset).lstrip()

            condstack[-1].append(
                parserdata.SetVariable(e,
                                       value=value,
                                       valueloc=d.getloc(offset),
                                       token=token,
                                       targetexp=None))
        else:
            doublecolon = token == '::'

            # `e` is targets or target patterns, which can end up as
            # * a rule
            # * an implicit rule
            # * a static pattern rule
            # * a target-specific variable definition
            # * a pattern-specific variable definition
            # any of the rules may have order-only prerequisites
            # delimited by |, and a command delimited by ;
            targets = e

            e, token, offset = parsemakesyntax(d, offset,
                                               _varsettokens + (':', '|', ';'),
                                               itermakefilechars)
            if token in (None, ';'):
                condstack[-1].append(parserdata.Rule(targets, e, doublecolon))
                currule = True

                if token == ';':
                    offset = d.skipwhitespace(offset)
                    e, t, offset = parsemakesyntax(d, offset, (),
                                                   itercommandchars)
                    condstack[-1].append(parserdata.Command(e))

            elif token in _varsettokens:
                e.lstrip()
                e.rstrip()

                value = flattenmakesyntax(d, offset).lstrip()
                condstack[-1].append(
                    parserdata.SetVariable(e,
                                           value=value,
                                           valueloc=d.getloc(offset),
                                           token=token,
                                           targetexp=targets))
            elif token == '|':
                raise SyntaxError('order-only prerequisites not implemented',
                                  d.getloc(offset))
            else:
                assert token == ':'
                # static pattern rule

                pattern = e

                deps, token, offset = parsemakesyntax(d, offset, (';', ),
                                                      itermakefilechars)

                condstack[-1].append(
                    parserdata.StaticPatternRule(targets, pattern, deps,
                                                 doublecolon))
                currule = True

                if token == ';':
                    offset = d.skipwhitespace(offset)
                    e, token, offset = parsemakesyntax(d, offset, (),
                                                       itercommandchars)
                    condstack[-1].append(parserdata.Command(e))

    if len(condstack) != 1:
        raise SyntaxError("Condition never terminated with endif",
                          condstack[-1].loc)

    return condstack[0]
Ejemplo n.º 4
0
def parsestream(fd, filename):
    """
    Parse a stream of makefile into a parserdata.StatementList. To parse a file system file, use
    parsefile instead of this method.

    @param fd A file-like object containing the makefile data.
    """

    currule = False
    condstack = [parserdata.StatementList()]

    fdlines = enumerate(fd)

    while True:
        assert len(condstack) > 0

        d = DynamicData(fdlines, filename)
        if d.data is None:
            break

        if len(d.data) > 0 and d.data[0] == '\t' and currule:
            e, t, o = parsemakesyntax(d, 1, (), itercommandchars)
            assert t == None
            condstack[-1].append(parserdata.Command(e))
        else:
            # To parse Makefile syntax, we first strip leading whitespace and
            # look for initial keywords. If there are no keywords, it's either
            # setting a variable or writing a rule.

            offset = d.skipwhitespace(0)

            kword, offset = d.findtoken(offset, _directivestokenlist, True)
            if kword == 'endif':
                _ensureend(d, offset,
                           "Unexpected data after 'endif' directive")
                if len(condstack) == 1:
                    raise SyntaxError("unmatched 'endif' directive",
                                      d.getloc(offset))

                condstack.pop()
                continue

            if kword == 'else':
                if len(condstack) == 1:
                    raise SyntaxError("unmatched 'else' directive",
                                      d.getloc(offset))

                kword, offset = d.findtoken(offset,
                                            _conditionkeywordstokenlist, True)
                if kword is None:
                    _ensureend(d, offset,
                               "Unexpected data after 'else' directive.")
                    condstack[-1].addcondition(d.getloc(offset),
                                               parserdata.ElseCondition())
                else:
                    if kword not in _conditionkeywords:
                        raise SyntaxError(
                            "Unexpected condition after 'else' directive.",
                            d.getloc(offset))

                    c = _conditionkeywords[kword](d, offset)
                    condstack[-1].addcondition(d.getloc(offset), c)
                continue

            if kword in _conditionkeywords:
                c = _conditionkeywords[kword](d, offset)
                cb = parserdata.ConditionBlock(d.getloc(0), c)
                condstack[-1].append(cb)
                condstack.append(cb)
                continue

            if kword == 'endef':
                raise SyntaxError("Unmatched endef", d.getloc(offset))

            if kword == 'define':
                currule = False
                vname, t, i = parsemakesyntax(d, offset, (), itermakefilechars)
                vname.rstrip()

                startpos = len(d.data)
                if not d.readline():
                    raise SyntaxError("Unterminated define", d.getloc())

                value = _iterflatten(iterdefinechars, d, startpos)
                condstack[-1].append(
                    parserdata.SetVariable(vname,
                                           value=value,
                                           valueloc=d.getloc(0),
                                           token='=',
                                           targetexp=None))
                continue

            if kword in ('include', '-include'):
                currule = False
                incfile, t, offset = parsemakesyntax(d, offset, (),
                                                     itermakefilechars)
                condstack[-1].append(
                    parserdata.Include(incfile, kword == 'include'))

                continue

            if kword == 'vpath':
                currule = False
                e, t, offset = parsemakesyntax(d, offset, (),
                                               itermakefilechars)
                condstack[-1].append(parserdata.VPathDirective(e))
                continue

            if kword == 'override':
                currule = False
                vname, token, offset = parsemakesyntax(d, offset,
                                                       _varsettokens,
                                                       itermakefilechars)
                vname.lstrip()
                vname.rstrip()

                if token is None:
                    raise SyntaxError("Malformed override directive, need =",
                                      d.getloc(offset))

                value = _iterflatten(itermakefilechars, d, offset).lstrip()

                condstack[-1].append(
                    parserdata.SetVariable(
                        vname,
                        value=value,
                        valueloc=d.getloc(offset),
                        token=token,
                        targetexp=None,
                        source=data.Variables.SOURCE_OVERRIDE))
                continue

            if kword == 'export':
                currule = False
                e, token, offset = parsemakesyntax(d, offset, _varsettokens,
                                                   itermakefilechars)
                e.lstrip()
                e.rstrip()

                if token is None:
                    condstack[-1].append(
                        parserdata.ExportDirective(e, single=False))
                else:
                    condstack[-1].append(
                        parserdata.ExportDirective(e, single=True))

                    value = _iterflatten(itermakefilechars, d, offset).lstrip()
                    condstack[-1].append(
                        parserdata.SetVariable(e,
                                               value=value,
                                               valueloc=d.getloc(offset),
                                               token=token,
                                               targetexp=None))

                continue

            if kword == 'unexport':
                e, token, offset = parsemakesyntax(d, offset, (),
                                                   itermakefilechars)
                condstack[-1].append(parserdata.UnexportDirective(e))
                continue

            assert kword is None, "unexpected kword: %r" % (kword, )

            e, token, offset = parsemakesyntax(d, offset,
                                               _varsettokens + ('::', ':'),
                                               itermakefilechars)
            if token is None:
                e.rstrip()
                e.lstrip()
                if not e.isempty():
                    condstack[-1].append(parserdata.EmptyDirective(e))
                continue

            # if we encountered real makefile syntax, the current rule is over
            currule = False

            if token in _varsettokens:
                e.lstrip()
                e.rstrip()

                value = _iterflatten(itermakefilechars, d, offset).lstrip()

                condstack[-1].append(
                    parserdata.SetVariable(e,
                                           value=value,
                                           valueloc=d.getloc(offset),
                                           token=token,
                                           targetexp=None))
            else:
                doublecolon = token == '::'

                # `e` is targets or target patterns, which can end up as
                # * a rule
                # * an implicit rule
                # * a static pattern rule
                # * a target-specific variable definition
                # * a pattern-specific variable definition
                # any of the rules may have order-only prerequisites
                # delimited by |, and a command delimited by ;
                targets = e

                e, token, offset = parsemakesyntax(
                    d, offset, _varsettokens + (':', '|', ';'),
                    itermakefilechars)
                if token in (None, ';'):
                    condstack[-1].append(
                        parserdata.Rule(targets, e, doublecolon))
                    currule = True

                    if token == ';':
                        offset = d.skipwhitespace(offset)
                        e, t, offset = parsemakesyntax(d, offset, (),
                                                       itercommandchars)
                        condstack[-1].append(parserdata.Command(e))

                elif token in _varsettokens:
                    e.lstrip()
                    e.rstrip()

                    value = _iterflatten(itermakefilechars, d, offset).lstrip()
                    condstack[-1].append(
                        parserdata.SetVariable(e,
                                               value=value,
                                               valueloc=d.getloc(offset),
                                               token=token,
                                               targetexp=targets))
                elif token == '|':
                    raise SyntaxError(
                        'order-only prerequisites not implemented',
                        d.getloc(offset))
                else:
                    assert token == ':'
                    # static pattern rule

                    pattern = e

                    deps, token, offset = parsemakesyntax(
                        d, offset, (';', ), itermakefilechars)

                    condstack[-1].append(
                        parserdata.StaticPatternRule(targets, pattern, deps,
                                                     doublecolon))
                    currule = True

                    if token == ';':
                        offset = d.skipwhitespace(offset)
                        e, token, offset = parsemakesyntax(
                            d, offset, (), itercommandchars)
                        condstack[-1].append(parserdata.Command(e))

    if len(condstack) != 1:
        raise SyntaxError("Condition never terminated with endif",
                          condstack[-1].loc)

    return condstack[0]