static void buildStateMachine()

in src/main/java/org/apache/xmlbeans/impl/schema/StscComplexTypeResolver.java [1544:1720]


    static void buildStateMachine(SchemaParticle contentModel) {
        if (contentModel == null) {
            return;
        }

        SchemaParticleImpl partImpl = (SchemaParticleImpl) contentModel;
        if (partImpl.hasTransitionNotes()) {
            return;
        }

        QNameSetBuilder start = new QNameSetBuilder();
        QNameSetBuilder excludenext = new QNameSetBuilder();
        boolean deterministic = true;
        SchemaParticle[] children;
        boolean canskip = (partImpl.getMinOccurs().signum() == 0);

        switch (partImpl.getParticleType()) {
            case SchemaParticle.ELEMENT:
                // compute start and excludeNext; canskip is already correct
                if (partImpl.hasTransitionRules()) {
                    start.addAll(partImpl.acceptedStartNames());
                } else {
                    start.add(partImpl.getName());
                }

                break;

            case SchemaParticle.WILDCARD:
                // compute start and excludeNext; canskip is already correct
                start.addAll(partImpl.getWildcardSet());
                break;

            case SchemaParticle.SEQUENCE:
                children = ensureStateMachine(partImpl.getParticleChildren());

                // adjust canskip if all children are skippable
                canskip = true;
                for (int i = 0; canskip && i < children.length; i++) {
                    if (!(children[i]).isSkippable()) {
                        canskip = false;
                    }
                }

                // bubble up nondeterministic bit
                for (SchemaParticle child : children) {
                    if (!((SchemaParticleImpl) child).isDeterministic()) {
                        deterministic = false;
                        break;
                    }
                }

                // verify deterministic and compute excludeNext set
                for (int i = 1; i < children.length; i++) {
                    excludenext.addAll(((SchemaParticleImpl) children[i - 1]).getExcludeNextSet());
                    if (deterministic && !excludenext.isDisjoint((children[i]).acceptedStartNames())) {
                        deterministic = false;
                    }
                    if ((children[i]).isSkippable()) {
                        excludenext.addAll((children[i]).acceptedStartNames());
                    } else {
                        excludenext.clear();
                    }
                }

                // next, compute start set
                for (SchemaParticle child : children) {
                    start.addAll(child.acceptedStartNames());
                    if (!child.isSkippable()) {
                        break;
                    }
                }
                break;

            case SchemaParticle.CHOICE:
                children = ensureStateMachine(partImpl.getParticleChildren());

                // adjust canskip if any children are skippable
                canskip = false;
                for (SchemaParticle schemaParticle : children) {
                    if (schemaParticle.isSkippable()) {
                        canskip = true;
                        break;
                    }
                }

                // bubble up nondeterministic bit
                for (SchemaParticle child : children) {
                    if (!((SchemaParticleImpl) child).isDeterministic()) {
                        deterministic = false;
                        break;
                    }
                }

                // compute start and excludeNext sets, verify deterministic
                for (SchemaParticle child : children) {
                    if (deterministic && !start.isDisjoint(child.acceptedStartNames())) {
                        deterministic = false;
                    }
                    start.addAll(child.acceptedStartNames());
                    excludenext.addAll(((SchemaParticleImpl) child).getExcludeNextSet());
                }

                break;

            case SchemaParticle.ALL:
                children = ensureStateMachine(partImpl.getParticleChildren());

                // adjust canskip if all children are skippable
                canskip = true;
                for (SchemaParticle child : children) {
                    if (!child.isSkippable()) {
                        canskip = false;
                        break;
                    }
                }

                // bubble up nondeterministic bit
                for (SchemaParticle child : children) {
                    if (!((SchemaParticleImpl) child).isDeterministic()) {
                        deterministic = false;
                        break;
                    }
                }

                // compute start and excludeNext sets, verify deterministic
                for (SchemaParticle child : children) {
                    if (deterministic && !start.isDisjoint(child.acceptedStartNames())) {
                        deterministic = false;
                    }
                    start.addAll(child.acceptedStartNames());
                    excludenext.addAll(((SchemaParticleImpl) child).getExcludeNextSet());
                }
                if (canskip) {
                    excludenext.addAll(start);
                }

                break;

            default:
                throw new IllegalStateException("Unrecognized schema particle");
        }

        // apply looping logic

        BigInteger minOccurs = partImpl.getMinOccurs();
        BigInteger maxOccurs = partImpl.getMaxOccurs();
        boolean canloop = (maxOccurs == null || maxOccurs.compareTo(BigInteger.ONE) > 0);
        boolean varloop = (maxOccurs == null || minOccurs.compareTo(maxOccurs) < 0);

        if (canloop && deterministic && !excludenext.isDisjoint(start)) {
            // we have a possible looping nondeterminism.
            // let's take some time now to see if it's actually caused
            // by non-unique-particle-attribute or not.
            QNameSet suspectSet = excludenext.intersect(start);

            // compute the set of all particles that could start this group
            Map<SchemaParticle, QNameSet> startMap = new HashMap<>();
            particlesMatchingStart(partImpl, suspectSet, startMap, new QNameSetBuilder());

            // compute the set of all particles that could have been repeated rather than ending this group
            Map<SchemaParticle, QNameSet> afterMap = new HashMap<>();
            particlesMatchingAfter(partImpl, suspectSet, afterMap, new QNameSetBuilder(), true);

            // see if we can find a member of after that is not a member of start
            // if we can, then particle attribution is not unique
            deterministic = afterMapSubsumedByStartMap(startMap, afterMap);
        }

        if (varloop) {
            excludenext.addAll(start);
        }

        canskip = canskip || minOccurs.signum() == 0;

        partImpl.setTransitionRules(start.toQNameSet(), canskip);
        partImpl.setTransitionNotes(excludenext.toQNameSet(), deterministic);
    }