示例#1
0
 /// <summary>
 /// Creates a new Query object with the specified arguments.
 /// </summary>
 /// <param name="name">The name of the dictionary to search.</param>
 /// <param name="subtype">The subtype of the dictionary entry to use.</param>
 /// <param name="carrier">The carrier for the query.</param>
 /// <param name="exclusive">Specifies exclusivity of class filters.</param>
 /// <param name="classFilters">The class filters to search by.</param>
 /// <param name="regexFilters">The regex filters to search by.</param>
 /// <param name="syllableRange">The syllable range to constrain results to.</param>
 public Query(string name, string subtype, Carrier carrier, bool exclusive, IEnumerable <_ <bool, string>[]> classFilters,
              IEnumerable <_ <bool, Regex> > regexFilters, SyllablePredicateFunc syllableRange)
 {
     _name          = name;
     _subtype       = subtype;
     _exclusive     = exclusive;
     _carrier       = carrier;
     _classFilters  = (classFilters ?? Enumerable.Empty <_ <bool, string>[]>()).AsEnumerable();
     _regexFilters  = (regexFilters ?? Enumerable.Empty <_ <bool, Regex> >()).AsEnumerable();
     _syllableRange = syllableRange;
 }
示例#2
0
        private static bool DoQuery(VM interpreter, Token <R> firstToken, PatternReader reader, State state)
        {
            reader.SkipSpace();

            bool   storeMacro    = false;
            bool   macroIsGlobal = false;
            string macroName     = null;

            // Check if this is a macro
            if (reader.Take(R.At))
            {
                reader.SkipSpace();

                var macroNameToken = reader.Read(R.Text, "query macro name");

                macroName = macroNameToken.Value;

                reader.SkipSpace();

                // Check if the macro is a definition or a call.
                // A definition will start with a colon ':' or equals '=' after the name. A call will only consist of the name.
                switch (reader.ReadToken().ID)
                {
                case R.Colon:     // Local definition
                {
                    if (!ValidateName(macroNameToken.Value))
                    {
                        throw Error(reader.Source, macroNameToken, "Invalid macro name: '\{macroNameToken.Value}'");
                    }
                    storeMacro = true;
                }
                break;

                case R.Equal:     // Global definition
                {
                    if (!ValidateName(macroNameToken.Value))
                    {
                        throw Error(reader.Source, macroNameToken, "Invalid macro name: '\{macroNameToken.Value}'");
                    }
                    storeMacro    = true;
                    macroIsGlobal = true;
                }
                break;

                case R.RightAngle:     // Call
                {
                    Query q;
                    var   mNameSub = macroNameToken.Value.Split(new[] { '.' }, StringSplitOptions.None);
                    if (!interpreter.LocalQueryMacros.TryGetValue(mNameSub[0], out q) && !interpreter.Engine.GlobalQueryMacros.TryGetValue(mNameSub[0], out q))
                    {
                        throw new RantException(reader.Source, macroNameToken, "Nonexistent query macro '\{macroName}'");
                    }
                    if (mNameSub.Length > 2)
                    {
                        throw Error(reader.Source, firstToken, "Invald subtype accessor on macro call.");
                    }
                    var oldSub = q.Subtype;
                    if (mNameSub.Length == 2)
                    {
                        q.Subtype = mNameSub[1];
                    }
                    interpreter.Print(interpreter.Engine.Dictionary?.Query(interpreter.RNG, q, interpreter.QueryState));
                    q.Subtype = oldSub;
                    return(false);
                }
                }
            }
            else if (reader.Take(R.DoubleColon)) // Carrier reset
            {
                Token <R> token;

                while ((token = reader.ReadToken()).ID != R.RightAngle)
                {
                    switch (token.ID)
                    {
                    case R.At:
                        interpreter.QueryState.DeleteAssociation(reader.ReadLoose(R.Text, "associative carrier name").Value);
                        break;

                    case R.Exclamation:
                        interpreter.QueryState.DeleteUnique(reader.ReadLoose(R.Text, "unique carrier name").Value);
                        break;

                    case R.Equal:
                        interpreter.QueryState.DeleteMatch(reader.ReadLoose(R.Text, "match carrier name").Value);
                        break;

                    case R.Ampersand:
                        interpreter.QueryState.DeleteRhyme(reader.ReadLoose(R.Text, "rhyme carrier name").Value);
                        break;

                    default:
                        throw Error(reader.Source, token, "Unrecognized token in carrier reset: '\{token.Value}'");
                    }
                    reader.SkipSpace();
                }
                return(false);
            }

            reader.SkipSpace();
            var namesub = reader.Read(R.Text, "dictionary name").Split(new[] { '.' }, 2).ToArray();

            reader.SkipSpace();

            bool exclusive = reader.Take(R.Dollar);
            List <Tuple <bool, string> >  cfList          = null;
            List <Tuple <bool, string>[]> classFilterList = null;
            List <Tuple <bool, Regex> >   regList         = null;
            Carrier carrier = null;
            SyllablePredicateFunc syllableRange = null;

            Token <R> queryToken = null;

            if (reader.IsNext(R.RangeLiteral))
            {
                syllableRange = SyllablePredicate.Create(reader.ReadToken());
            }

            // Read query arguments
            while (true)
            {
                reader.SkipSpace();
                if (reader.Take(R.Hyphen))
                {
                    reader.SkipSpace();
                    // Initialize the filter list.
                    (cfList ?? (cfList = new List <Tuple <bool, string> >())).Clear();
                    do
                    {
                        bool notin = reader.Take(R.Exclamation);
                        reader.SkipSpace();
                        if (notin && exclusive)
                        {
                            throw new RantException(reader.Source, reader.PrevToken, "Cannot use the '!' modifier on exclusive class filters.");
                        }
                        cfList.Add(Tuple.Create(!notin, reader.Read(R.Text, "class identifier").Value.Trim()));
                        reader.SkipSpace();
                    } while (reader.Take(R.Pipe));
                    (classFilterList ?? (classFilterList = new List <Tuple <bool, string>[]>())).Add(cfList.ToArray());
                }
                else if (reader.Take(R.Question))
                {
                    reader.SkipSpace();
                    queryToken = reader.Read(R.Regex, "regex");
                    (regList ?? (regList = new List <Tuple <bool, Regex> >())).Add(Tuple.Create(true, ParseRegex(queryToken.Value)));
                }
                else if (reader.Take(R.Without))
                {
                    reader.SkipSpace();
                    queryToken = reader.Read(R.Regex, "regex");
                    (regList ?? (regList = new List <Tuple <bool, Regex> >())).Add(Tuple.Create(false, ParseRegex(queryToken.Value)));
                }
                else if (reader.Take(R.DoubleColon)) // Start of carrier
                {
                    reader.SkipSpace();

                    carrier = new Carrier();
                    Token <R>        typeToken;
                    CarrierComponent comp = CarrierComponent.Match;

                    while ((typeToken = reader.ReadToken()).ID != R.RightAngle)
                    {
                        switch (typeToken.ID)
                        {
                        case R.Exclamation:     // Unique
                            comp = reader.Take(R.Equal) ? CarrierComponent.MatchUnique : CarrierComponent.Unique;
                            break;

                        case R.Equal:     // Match
                            comp = CarrierComponent.Match;
                            break;

                        case R.Ampersand:     // Rhyme
                            comp = CarrierComponent.Rhyme;
                            break;

                        case R.At:     // Associative/Relational/Dissociative/Divergent
                        {
                            if (reader.Take(R.Question))
                            {
                                comp = reader.Take(R.Equal) ? CarrierComponent.MatchRelational : CarrierComponent.Relational;
                            }
                            else if (reader.Take(R.Exclamation))
                            {
                                comp = reader.Take(R.Equal) ? CarrierComponent.MatchDissociative : CarrierComponent.Dissociative;
                            }
                            else if (reader.Take(R.Plus))
                            {
                                comp = reader.Take(R.Equal) ? CarrierComponent.MatchDivergent : CarrierComponent.Divergent;
                            }
                            else
                            {
                                comp = reader.Take(R.Equal) ? CarrierComponent.MatchAssociative : CarrierComponent.Associative;
                            }
                        }
                        break;

                        default:
                            throw new RantException(reader.Source, typeToken, "Unrecognized token '\{typeToken.Value}' in carrier.");
                        }
                        carrier.AddComponent(comp, reader.ReadLoose(R.Text, "carrier component name").Value);
                        reader.SkipSpace();
                    }

                    break;
                }