Example #1
0
 public CrstType(string name)
 {
     m_name  = name;
     m_level = CrstUnassigned;
     m_acquiredBeforeCrsts = new List <CrstType>();
     m_group   = null;
     m_defined = false;
 }
Example #2
0
    // Declare a SameLevelAs relationship between the two Crst types given. Groups will be assigned, created
    // or merged as required to maintain our guarantees (each CrstType is a member of at most one group and
    // all CrstTypes involved in the same transitive closure of a SameLevelAs relationship are members of one
    // group).
    public static void Join(CrstType crst1, CrstType crst2)
    {
        CrstTypeGroup group;

        if (crst1 == crst2)
        {
            // In this case the type refers to itself. Create a singleton group for this type if it doesn't
            // already exist.
            if (crst1.Group == null)
            {
                group = new CrstTypeGroup();
                group.m_members.Add(crst1);

                s_groups.Add(group);

                crst1.Group = group;
            }
        }
        else if (crst1.Group == null && crst2.Group == null)
        {
            // Neither types belong to a group already. So we can create a new one and add both types to it.
            group = new CrstTypeGroup();
            group.m_members.Add(crst1);
            group.m_members.Add(crst2);

            s_groups.Add(group);

            crst1.Group = group;
            crst2.Group = group;
        }
        else if (crst1.Group == null)
        {
            // The first type doesn't belong to a group yet but the second does. So we can simply add the
            // first type to the second group.
            group = crst2.Group;
            group.m_members.Add(crst1);

            crst1.Group = group;
        }
        else if (crst2.Group == null)
        {
            // As for the case above but the group/no-group positions are reversed.
            group = crst1.Group;
            group.m_members.Add(crst2);

            crst2.Group = group;
        }
        else if (crst1.Group != crst2.Group)
        {
            // Both types belong to different groups so we'll have to merge them. Add the members of group 2
            // to group 1 and throw away group 2.
            group = crst1.Group;
            CrstTypeGroup absorbGroup = crst2.Group;
            foreach (CrstType crst in absorbGroup.m_members)
            {
                group.m_members.Add(crst);
                crst.Group = group;
            }

            s_groups.Remove(absorbGroup);
        }

        // The only case left is when both types are already in the same group and there's no work needed in
        // this case.
    }
Example #3
0
    // Parse a single Crst type definition.
    void ParseCrst()
    {
        // The next token had better be an identifier (the Crst type name).
        Token token = NextToken();

        if (token.Id != KeywordId.Id)
        {
            throw new UnexpectedTokenError(token, KeywordId.Id);
        }

        // The Crst instance might already exist in the dictionary (forward references to a Crst type cause
        // these entries to auto-vivify). But in that case the entry better not be marked as 'Defined' which
        // would indicate a double declaration.
        CrstType crst;

        if (m_crsts.ContainsKey(token.Text))
        {
            crst = m_crsts[token.Text];
            if (crst.Defined)
            {
                throw new ParseError(String.Format("Duplicate definition for CrstType '{0}'", token.Text), token);
            }
        }
        else
        {
            // Otherwise this Crst type hasn't been seen thus far so we allocate a new instance and add it to
            // the dictionary.
            crst = new CrstType(token.Text);
            m_crsts.Add(crst.Name, crst);
        }

        // We're defining, not just referencing this type.
        crst.Defined = true;

        // Parse any attributes inside this definition (until we see an 'End' token).
        bool parsingCrst = true;

        while (parsingCrst)
        {
            // Get the next token. Either some attribute keyword or 'End'.
            token = NextToken();
            List <CrstType> list;

            switch (token.Id)
            {
            case KeywordId.AcquiredBefore:
                // Simply parse the following list of Crst types into the current type's AcquiredBefore list.
                ParseList(crst.AcquiredBeforeList);
                break;

            case KeywordId.AcquiredAfter:
                // AcquiredAfter is trickier. To make the ranking algorithm's life easier we actually
                // normalize all rules to the AcquiredBefore form (see LevelCrsts() for the reasoning). So we
                // capture the list of Crst types that follow the AcquiredAfter keyword and then append the
                // current type to the AcquiredBefore list of each type found.
                list = new List <CrstType>();
                ParseList(list);
                foreach (CrstType priorCrst in list)
                {
                    priorCrst.AcquiredBeforeList.Add(crst);
                }
                break;

            case KeywordId.SameLevelAs:
                // Parse the following list of Crst types them let the CrstTypeGroup class handle the
                // resulting updates to the type groups we're currently maintaining. See the comments for the
                // CrstTypeGroup class for more details.
                list = new List <CrstType>();
                ParseList(list);
                foreach (CrstType sameLevelCrst in list)
                {
                    CrstTypeGroup.Join(crst, sameLevelCrst);
                }
                break;

            case KeywordId.Unordered:
                crst.Level = CrstType.CrstUnordered;
                break;

            case KeywordId.End:
                parsingCrst = false;
                break;

            default:
                throw new UnexpectedTokenError(token,
                                               KeywordId.AcquiredBefore,
                                               KeywordId.AcquiredAfter,
                                               KeywordId.SameLevelAs,
                                               KeywordId.Unordered);
            }
        }
    }
Example #4
0
    // Peform checking of the Crst type definitions we've read just read. Various forms of logic error are
    // scanned for including cycles in the dependency graph. Returns true if no errors are found. If false is
    // returned a descriptive error message will have already been written to the console.
    bool ValidateCrsts()
    {
        // Look at each Crst type definition in turn.
        foreach (CrstType crst in m_crsts.Values)
        {
            // Catch Crst types that are referenced but never defined.
            if (!crst.Defined)
            {
                Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is referenced without being defined",
                                                crst.Name));
                return(false);
            }

            // Catch the use of the 'Unordered' attribute alongside the 'AcquiredBefore' attribute (which
            // indicates an ordering).
            if (crst.Level == CrstType.CrstUnordered && (crst.AcquiredBeforeList.Count > 0 ||
                                                         crst.Group != null))
            {
                Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is declared as both unordered and acquired before 'Crst{1}'",
                                                crst.Name, crst.AcquiredBeforeList[0].Name));
                return(false);
            }

            // Catch the use of the 'Unordered' attribute alongside the 'SameLevelAs' attribute (which
            // indicates an ordering).
            if (crst.Level == CrstType.CrstUnordered && crst.Group != null)
            {
                Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is declared as both unordered and in the same level as another CrstType",
                                                crst.Name));
                return(false);
            }

            // Catch the simple cycle where the Crst type depends on itself.
            if (crst.AcquiredBeforeList.Contains(crst))
            {
                Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is declared as being acquired before itself",
                                                crst.Name));
                return(false);
            }

            // Look for deeper cycles using a recursive algorithm in 'FindCycle()'.
            List <CrstType> cycleList = new List <CrstType>();
            if (FindCycle(crst, crst, cycleList))
            {
                Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is involved in a dependency cycle with the following CrstTypes:",
                                                crst.Name));
                foreach (CrstType cycleCrst in cycleList)
                {
                    Console.WriteLine(String.Format("    Crst{0}", cycleCrst.Name));
                }
                return(false);
            }
        }

        // Perform normalization of each set of Crst types that are included in the same group (i.e. have a
        // 'SameLevelAs' relationship). Normalization means that each Crst type in a group will have exactly
        // the same set of dependency rules as all the others.
        CrstTypeGroup.NormalizeAllRules();

        // The normalization process could have introduced cycles in the dependency graph so run the cycle
        // detection pass again. We do separate passes like this since normalizing can lead to less intuitive
        // error messages if a cycle is found: so if the cycle exists before normalization takes place we want
        // to generate an error message then.
        foreach (CrstType crst in m_crsts.Values)
        {
            List <CrstType> cycleList = new List <CrstType>();
            if (FindCycle(crst, crst, cycleList))
            {
                Console.WriteLine(String.Format("Error: CrstType 'Crst{0}' is involved in a dependency cycle with the following CrstTypes:",
                                                crst.Name));
                foreach (CrstType cycleCrst in cycleList)
                {
                    Console.WriteLine(String.Format("    Crst{0}", cycleCrst));
                }
                Console.WriteLine("Note that the cycle was detected only after 'SameLevelAs' processing was performed so some CrstType dependencies are implied by peer CrstTypes");
                return(false);
            }
        }

        return(true);
    }
Example #5
0
    // Declare a SameLevelAs relationship between the two Crst types given. Groups will be assigned, created
    // or merged as required to maintain our guarantees (each CrstType is a member of at most one group and
    // all CrstTypes involved in the same transitive closure of a SameLevelAs relationship are members of one
    // group).
    public static void Join(CrstType crst1, CrstType crst2)
    {
        CrstTypeGroup group;

        if (crst1 == crst2)
        {
            // In this case the type refers to itself. Create a singleton group for this type if it doesn't
            // already exist.
            if (crst1.Group == null)
            {
                group = new CrstTypeGroup();
                group.m_members.Add(crst1);

                s_groups.Add(group);

                crst1.Group = group;
            }
        }
        else if (crst1.Group == null && crst2.Group == null)
        {
            // Neither types belong to a group already. So we can create a new one and add both types to it.
            group = new CrstTypeGroup();
            group.m_members.Add(crst1);
            group.m_members.Add(crst2);

            s_groups.Add(group);

            crst1.Group = group;
            crst2.Group = group;
        }
        else if (crst1.Group == null)
        {
            // The first type doesn't belong to a group yet but the second does. So we can simply add the
            // first type to the second group.
            group = crst2.Group;
            group.m_members.Add(crst1);

            crst1.Group = group;
        }
        else if (crst2.Group == null)
        {
            // As for the case above but the group/no-group positions are reversed.
            group = crst1.Group;
            group.m_members.Add(crst2);

            crst2.Group = group;
        }
        else if (crst1.Group != crst2.Group)
        {
            // Both types belong to different groups so we'll have to merge them. Add the members of group 2
            // to group 1 and throw away group 2.
            group = crst1.Group;
            CrstTypeGroup absorbGroup = crst2.Group;
            foreach (CrstType crst in absorbGroup.m_members)
            {
                group.m_members.Add(crst);
                crst.Group = group;
            }

            s_groups.Remove(absorbGroup);
        }

        // The only case left is when both types are already in the same group and there's no work needed in
        // this case.
    }
Example #6
0
 public CrstType(string name)
 {
     m_name = name;
     m_level = CrstUnassigned;
     m_acquiredBeforeCrsts = new List<CrstType>();
     m_group = null;
     m_defined = false;
 }