Ejemplo n.º 1
0
        /// <summary>
        /// Finds sets recursively of type "pop" or "eol_pop".
        /// </summary>
        private static List <KeyValuePair <string, IroVariable> > FindPops(IroSet set, IroSet contexts)
        {
            //Loop over set members, for each include find pops too.
            var pops = new List <KeyValuePair <string, IroVariable> >();

            foreach (var member in set)
            {
                if (member.Value is IroSet)
                {
                    //Is it a pop or eol_pop?
                    var setMem = ((IroSet)member.Value);
                    if (setMem.SetType == "pop" || setMem.SetType == "eol_pop")
                    {
                        pops.Add(member);
                    }
                }

                //Is it an include?
                if (member.Value is IroInclude)
                {
                    var    include    = ((IroInclude)member.Value);
                    string includeCtx = include.Value;

                    //Try and find context to evaluate.
                    if (!contexts.ContainsKey(includeCtx) || !(contexts[includeCtx] is IroSet))
                    {
                        Error.Compile("Include statement references context '" + includeCtx + "', but it does not exist.");
                        return(null);
                    }
                    var ctx = (IroSet)contexts[includeCtx];

                    //Find pops in there, add range.
                    pops.AddRange(FindPops(ctx, contexts));
                }
            }

            //Return list.
            return(pops);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Parses a single pattern from a context.
        /// </summary>
        private static ContextMember ParsePattern(IroSet value)
        {
            //Find the mandatory "styles" and "regex" properties.
            if (!value.ContainsKey("regex") || !value.ContainsKey("styles"))
            {
                Error.Compile("Pattern missing a required attribute (must have 'styles' and 'regex').");
                return(null);
            }

            //Valid types?
            string regex;

            if (value["styles"].Type != VariableType.Array)
            {
                Error.Compile("Pattern 'styles' attribute must be an array.");
                return(null);
            }
            if (value["regex"].Type != VariableType.Regex)
            {
                if (value["regex"].Type == VariableType.Reference)
                {
                    var constant = GetConstant(((IroReference)value["regex"]).Value, VariableType.Regex);
                    if (constant is IroValue)
                    {
                        regex = ((IroValue)constant).Value;
                    }
                    else
                    {
                        regex = ((IroRegex)constant).StringValue;
                    }
                }
                else
                {
                    Error.Compile("Pattern 'regex' attribute must be a regex value.");
                    return(null);
                }
            }
            else
            {
                regex = ((IroRegex)value["regex"]).StringValue;
            }

            //Get them out.
            List <string> styles = new List <string>();

            foreach (var style in ((IroList)value["styles"]))
            {
                //Is the value a name?
                if (!(style is IroValue))
                {
                    Error.CompileWarning("Failed to add pattern style for pattern with regex '" + regex + "', array member is not a value.");
                    continue;
                }

                //Get the name out and add it.
                styles.Add(((IroValue)style).Value);
            }

            //Create a pattern.
            return(new PatternContextMember()
            {
                Data = regex,
                Styles = styles,
                Type = ContextMemberType.Pattern
            });
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Parses a single inline push context member in Iro.
        /// </summary>
        private static ContextMember ParseInlinePush(IroSet ilp, IroSet contexts)
        {
            //Find the required elements 'regex', 'styles' and 'pop'.
            if (!ilp.ContainsKey("regex") || !ilp.ContainsKey("styles"))
            {
                Error.Compile("Required attribute is missing from inline push (must have members 'regex', 'styles').");
                return(null);
            }
            if (!ilp.ContainsSetOfType("pop") && !ilp.ContainsSetOfType("eol_pop"))
            {
                //No pops or eol_pops here. Try to find one in children.
                var popsFound = FindPops(ilp, contexts);
                if (popsFound.Count == 0)
                {
                    Error.Compile("Inline push patterns must have a 'pop' or 'eol_pop' set to know when to end the state.");
                    return(null);
                }
                if (popsFound.Count > 1)
                {
                    Error.Compile("Inline push patterns can only contain one 'pop' or 'eol_pop' rule. It appears multiple 'pop's are imported from other contexts.");
                    return(null);
                }

                //Add the relevant set to the ILP.
                ilp.Add(popsFound[0]);
            }
            if (ilp.ContainsSetOfType("pop") && ilp.ContainsSetOfType("eol_pop"))
            {
                Error.Compile("Inline push patterns cannot hav both a 'pop' and an 'eol_pop', you must use one or the other.");
                return(null);
            }

            //Verify their types.
            string regex;

            if (!(ilp["regex"] is IroRegex))
            {
                //Is it a constant yet to be converted?
                if ((ilp["regex"] is IroReference))
                {
                    //Attempt to get the constant.
                    IroVariable constant = GetConstant(((IroReference)ilp["regex"]).Value, VariableType.Regex);
                    if (constant is IroRegex)
                    {
                        regex = ((IroRegex)constant).StringValue;
                    }
                    else
                    {
                        regex = ((IroValue)constant).Value;
                    }
                }
                else
                {
                    Error.Compile("Inline push attribute 'regex' must be a regex value.");
                    return(null);
                }
            }
            if (!(ilp["styles"] is IroList))
            {
                Error.Compile("Inline push attribute 'styles' must be an array value.");
                return(null);
            }
            if (ilp.ContainsSetOfType("pop") && !(ilp.GetFirstSetOfType("pop") is IroSet))
            {
                Error.Compile("Pop attributes must be a set.");
                return(null);
            }
            if (ilp.ContainsSetOfType("eol_pop") && !(ilp.GetFirstSetOfType("eol_pop") is IroSet))
            {
                Error.Compile("End of line pop attributes must be a set.");
                return(null);
            }

            //Get out the regex and style values.
            regex = ((IroRegex)ilp["regex"]).StringValue;
            List <string> styles = new List <string>();

            foreach (var style in ((IroList)ilp["styles"]))
            {
                //Is the value a name?
                if (!(style is IroValue))
                {
                    Error.CompileWarning("Failed to add pattern style for pattern with regex '" + regex + "', array member is not a value.");
                    continue;
                }

                //Get the name out and add it.
                styles.Add(((IroValue)style).Value);
            }

            //Generate the pop (if it's there).
            List <string> popStyles = new List <string>();
            string        popRegex;

            if (ilp.ContainsSetOfType("pop"))
            {
                //Parse the 'pop'.
                var pop = ilp.GetFirstSetOfType("pop");
                if (!pop.ContainsKey("regex"))
                {
                    Error.Compile("Inline push 'pop' messages must contain a 'regex' property.");
                    return(null);
                }
                if (!(pop["regex"] is IroValue) && !(pop["regex"] is IroRegex))
                {
                    Error.Compile("Inline push 'pop' messages must contain a 'regex' property of type 'regex'.");
                }
                if (!pop.ContainsKey("styles") || pop["styles"].Type != VariableType.Array)
                {
                    Error.Compile("Inline push 'pop' messages must have a 'styles' attribute of type 'array'.");
                    return(null);
                }

                //get regex
                if (pop["regex"] is IroReference)
                {
                    //It's a constant, uh oh. Get it.
                    var const_ = GetConstant(((IroReference)pop["regex"]).Value, VariableType.Regex);
                    if (const_ is IroRegex)
                    {
                        popRegex = ((IroRegex)const_).StringValue;
                    }
                    else
                    {
                        popRegex = ((IroValue)const_).Value;
                    }
                }
                else
                {
                    popRegex = ((IroRegex)pop["regex"]).StringValue;
                }

                //styles
                foreach (var style in ((IroList)pop["styles"]))
                {
                    if (!(style is IroValue))
                    {
                        Error.CompileWarning("Failed to add 'pop' style for pattern with regex '" + regex + "', array member is not a value.");
                        continue;
                    }

                    //Get the name out and add it.
                    popStyles.Add(((IroValue)style).Value);
                }
            }
            else
            {
                //eol_pop
                popStyles = styles;
                popRegex  = "(\\n|\\r\\n)";
            }

            //Get all patterns and includes out.
            var patterns = ilp.Where(x => x.Value is IroSet && ((IroSet)x.Value).SetType == "pattern")
                           .Select(x => x.Value)
                           .Cast <IroSet>();

            var includes = ilp.Where(x => x.Value is IroInclude)
                           .Select(x => x.Value)
                           .Cast <IroValue>();

            var values = ilp.Where(x => x.Value.Type == VariableType.Value);

            var ctxMems = new List <ContextMember>();

            //Parse them into the context list.
            foreach (var pattern in patterns)
            {
                ctxMems.Add(ParsePattern(pattern));
            }
            foreach (var include in includes)
            {
                ctxMems.Add(new ContextMember()
                {
                    Data = include.Value,
                    Type = ContextMemberType.Include
                });
            }
            foreach (var value in values)
            {
                //Ignore the horrible spaghetti, first parameter is getting out the string value from the KeyValuePair.
                //Second is getting out the name.
                var ctxVal = AddContextValue(((IroValue)value.Value).Value, value.Key);
                if (ctxVal != null)
                {
                    ctxMems.Add(ctxVal);
                }
            }

            //Create the module and return it.
            return(new InlinePushContextMember()
            {
                Data = regex,
                Styles = styles,
                PopData = popRegex,
                PopStyles = popStyles,
                Patterns = ctxMems,
                Type = ContextMemberType.InlinePush
            });
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Processes a single context from the IroVariable form into an IroContext form.
        /// </summary>
        private static IroContext ProcessContext(string contextName, IroSet context, IroSet contexts)
        {
            var iroCtx = new IroContext(contextName);

            //Loop over the values in the context, process depending on type.
            foreach (var kvp in context)
            {
                var value = kvp.Value;

                //An include.
                if (value is IroInclude)
                {
                    iroCtx.Members.Add(new ContextMember()
                    {
                        Data = ((IroInclude)value).Value,
                        Type = ContextMemberType.Include
                    });
                }

                //A descriptive value for a set.
                else if (value is IroValue)
                {
                    var valueType = (IroValue)value;
                    var ctxVal    = AddContextValue(valueType.Value, kvp.Key);
                    if (ctxVal != null)
                    {
                        iroCtx.Members.Add(ctxVal);
                    }
                }

                //A set of a given type.
                else if (value is IroSet)
                {
                    switch (((IroSet)value).SetType)
                    {
                    case "inline_push":
                        iroCtx.Members.Add(ParseInlinePush((IroSet)value, contexts));
                        break;

                    case "pattern":
                        iroCtx.Members.Add(ParsePattern((IroSet)value));
                        break;

                    case "pop":
                        //Pop rules are never directly parsed, only used as a result of inline_push or push.
                        break;

                    case "push":
                        //todo: add push rules
                        throw new NotImplementedException();
                    }
                }

                //Unrecognized.
                else
                {
                    Error.Compile("Unrecognized statement inside an Iro context, must be a set or an include.");
                    return(null);
                }
            }

            return(iroCtx);
        }