def do_parse()

in lib/ramble/spack/spec.py [0:0]


    def do_parse(self):
        specs = []

        try:
            while self.next:
                # Try a file first, but if it doesn't succeed, keep parsing
                # as from_file may backtrack and try an id.
                if self.accept(FILE):
                    spec = self.spec_from_file()
                    if spec:
                        specs.append(spec)
                        continue

                if self.accept(ID):
                    self.previous = self.token
                    if self.accept(EQ):
                        # We're parsing an anonymous spec beginning with a
                        # key-value pair.
                        if not specs:
                            self.push_tokens([self.previous, self.token])
                            self.previous = None
                            specs.append(self.spec(None))
                        else:
                            if specs[-1].concrete:
                                # Trying to add k-v pair to spec from hash
                                raise RedundantSpecError(specs[-1],
                                                         'key-value pair')
                            # We should never end up here.
                            # This requires starting a new spec with ID, EQ
                            # After another spec that is not concrete
                            # If the previous spec is not concrete, this is
                            # handled in the spec parsing loop
                            # If it is concrete, see the if statement above
                            # If there is no previous spec, we don't land in
                            # this else case.
                            self.unexpected_token()
                    else:
                        # We're parsing a new spec by name
                        self.previous = None
                        specs.append(self.spec(self.token.value))
                elif self.accept(HASH):
                    # We're finding a spec by hash
                    specs.append(self.spec_by_hash())

                elif self.accept(DEP):
                    if not specs:
                        # We're parsing an anonymous spec beginning with a
                        # dependency. Push the token to recover after creating
                        # anonymous spec
                        self.push_tokens([self.token])
                        specs.append(self.spec(None))
                    else:
                        dep = None
                        if self.accept(FILE):
                            # this may return None, in which case we backtrack
                            dep = self.spec_from_file()

                        if not dep and self.accept(HASH):
                            # We're finding a dependency by hash for an
                            # anonymous spec
                            dep = self.spec_by_hash()
                            dep = dep.copy(deps=('link', 'run'))

                        if not dep:
                            # We're adding a dependency to the last spec
                            if self.accept(ID):
                                self.previous = self.token
                                if self.accept(EQ):
                                    # This is an anonymous dep with a key=value
                                    # push tokens to be parsed as part of the
                                    # dep spec
                                    self.push_tokens(
                                        [self.previous, self.token])
                                    dep_name = None
                                else:
                                    # named dep (standard)
                                    dep_name = self.token.value
                                self.previous = None
                            else:
                                # anonymous dep
                                dep_name = None
                            dep = self.spec(dep_name)

                        # Raise an error if the previous spec is already
                        # concrete (assigned by hash)
                        if specs[-1].concrete:
                            raise RedundantSpecError(specs[-1], 'dependency')
                        # command line deps get empty deptypes now.
                        # Real deptypes are assigned later per packages.
                        specs[-1]._add_dependency(dep, ())

                else:
                    # If the next token can be part of a valid anonymous spec,
                    # create the anonymous spec
                    if self.next.type in (AT, ON, OFF, PCT):
                        # Raise an error if the previous spec is already concrete
                        if specs and specs[-1].concrete:
                            raise RedundantSpecError(specs[-1],
                                                     'compiler, version, '
                                                     'or variant')
                        specs.append(self.spec(None))
                    else:
                        self.unexpected_token()

        except spack.parse.ParseError as e:
            raise SpecParseError(e) from e

        # Generate lookups for git-commit-based versions
        for spec in specs:
            # Cannot do lookups for versions in anonymous specs
            # Only allow Version objects to use git for now
            # Note: VersionRange(x, x) is currently concrete, hence isinstance(...).
            if (
                spec.name and spec.versions.concrete and
                isinstance(spec.version, vn.Version) and spec.version.is_commit
            ):
                spec.version.generate_commit_lookup(spec.fullname)

        return specs