Exemple #1
0
        /// <summary>
        /// Gets a list of styles for a specific pattern context member.
        /// </summary>
        private List <IroStyle> GetPatternStyles(List <string> styleNames, IroPrecompileData data)
        {
            //Check that styles exist, and try to get the first one out.
            if (styleNames.Count == 0)
            {
                Error.Compile("No style was defined for a pattern. All styles must have patterns.");
                return(null);
            }

            //Get all the patterns out.
            var styles = new List <IroStyle>();

            foreach (var style in styleNames)
            {
                //Get the styles form the style list.
                int index = data.Styles.FindIndex(x => x.Name == style);
                if (index == -1)
                {
                    Error.Compile("A style '" + style + "' is referenced in a pattern, but it is not defined in the style map.");
                    return(null);
                }

                styles.Add(data.Styles[index]);
            }

            //Make sure all the patterns have textmate scopes.
            if (styles.Where(x => x.TextmateScope != null).Count() != styles.Count)
            {
                Error.Compile("One or more styles for a pattern does not have a textmate scope defined.");
                return(null);
            }

            return(styles);
        }
Exemple #2
0
        /// <summary>
        /// Adds a single pattern to the list of patterns.
        /// </summary>
        private void AddPattern(ref StringBuilder text, ContextMember pattern, IroPrecompileData data)
        {
            //What type is it?
            switch (pattern.Type)
            {
            case ContextMemberType.Include:
                text.AppendLine("<dict>");
                text.AppendLine("<key>include</key>");
                text.AppendLine("<string>#" + pattern.Data + "</string>");
                text.AppendLine("</dict>");
                break;

            case ContextMemberType.Pattern:
                AddPatternRaw(ref text, (PatternContextMember)pattern, data);
                break;

            case ContextMemberType.InlinePush:
                AddInlinePush(ref text, (InlinePushContextMember)pattern, data);
                break;

            case ContextMemberType.Push:
                throw new NotImplementedException();

            case ContextMemberType.Pop:
                throw new NotImplementedException();

            default:
                Error.CompileWarning("Failed to add pattern, unrecognized context member type '" + pattern.Type.ToString() + "'.");
                return;
            }
        }
Exemple #3
0
        /// <summary>
        /// Adds a single context to the builder.
        /// </summary>
        private void AddContext(ref StringBuilder text, IroContext context, IroPrecompileData data)
        {
            text.AppendLine("<key>" + context.Name + "</key>");
            text.AppendLine("<dict>");

            //Define all the patterns in this context.
            text.AppendLine("<key>patterns</key>");
            text.AppendLine("<array>");
            foreach (var pattern in context.Members)
            {
                AddPattern(ref text, pattern, data);
            }
            text.AppendLine("</array>");
            text.AppendLine("</dict>");
        }
Exemple #4
0
        /// <summary>
        /// Compiles a set of Algo variables given targets.
        /// </summary>
        public static List <CompileResult> Compile(Dictionary <string, IroVariable> vars, params ICompileTarget[] targets)
        {
            //Set locals for this compile.
            Variables = vars;
            var pcd = new IroPrecompileData();

            //Parse all the top level flags.
            ParseTopLevelFlags(vars, ref pcd);

            //todo: parse other top level flags
            Error.CompileWarning("Some top-level flags are missing and/or not implemented yet.");

            //Find constants.
            var constants = vars.Select(x => x.Value.Type == VariableType.Value && x.Key.StartsWith("__")).Cast <IroValue>();

            //Check that the "styles" and "contexts" system sets are there.
            if (!vars.ContainsKey("styles") || vars["styles"].Type != VariableType.Set)
            {
                Error.Compile("The 'styles' set does not exist, you must define a list of styles to use for your grammar.");
                return(null);
            }
            if (!vars.ContainsKey("contexts") || vars["contexts"].Type != VariableType.Set)
            {
                Error.Compile("The 'contexts' set does not exist, you must define a list of contexts to pattern match your styles to.");
                return(null);
            }

            //Crawl through the styles set and define them in the list.
            var stylesSet = (IroSet)vars["styles"];

            foreach (var style in stylesSet)
            {
                var thisStyle = new IroStyle(style.Key);

                //Make sure this is an object, can't have any attributes in the styles list.
                if (style.Value.Type != VariableType.Set)
                {
                    //Skip the value.
                    Error.CompileWarning("A non-set value '" + style.Key + "' is defined in the styles map. Only style sets should be defined in the 'styles' map.");
                    continue;
                }

                var styleDefinition = (IroSet)style.Value;
                if (styleDefinition.SetType != "style")
                {
                    Error.CompileWarning("A set in the styles map is defined as having type '" + styleDefinition.SetType + "', which is not a style. Skipping.");
                    continue;
                }

                //Switch on all the values in that set and define style based on the keys.
                foreach (var styleProperty in styleDefinition)
                {
                    //Is the value a string?
                    if (styleProperty.Value.Type != VariableType.Value)
                    {
                        Error.CompileWarning("Failed to create style with name '" + style.Key + ", non-string value defined in the style object.");
                        continue;
                    }
                    string value = ((IroValue)styleProperty.Value).Value;

                    //Switch on the property.
                    switch (styleProperty.Key)
                    {
                    case "color":
                    case "colour":
                        thisStyle.Colour = value;
                        break;

                    case "background_colour":
                    case "background_color":
                    case "ace_scope":
                        thisStyle.AceScope = value;
                        break;

                    case "textmate_scope":
                        thisStyle.TextmateScope = value;
                        break;

                    case "pygments_scope":
                        thisStyle.PygmentsScope = value;
                        break;

                    case "highlight_js_scope":
                        thisStyle.HighlightJSScope = value;
                        break;

                    case "bold":
                        if (value == "true")
                        {
                            thisStyle.Bold = true;
                        }
                        else if (value == "false")
                        {
                            thisStyle.Bold = false;
                        }
                        else
                        {
                            Error.CompileWarning("Unrecognized value for boolean property 'bold', not 'true' or 'false'. Assumed 'false'.");
                            thisStyle.Bold = false;
                        }
                        break;

                    case "italic":
                        if (value == "true")
                        {
                            thisStyle.Italic = true;
                        }
                        else if (value == "false")
                        {
                            thisStyle.Italic = false;
                        }
                        else
                        {
                            Error.CompileWarning("Unrecognized value for boolean property 'bold', not 'true' or 'false'. Assumed 'false'.");
                            thisStyle.Italic = false;
                        }
                        break;

                    default:
                        Error.CompileWarning("Invalid property in style set '" + style.Key + "' with name '" + styleProperty.Key + "'.");
                        continue;
                    }
                }

                //Add the style to the list.
                pcd.Styles.Add(thisStyle);
            }

            //Styles are done processing, start processing the contexts.
            var contextsSet = (IroSet)vars["contexts"];

            foreach (var context in contextsSet)
            {
                //Is the set a context?
                if (context.Value.Type != VariableType.Set)
                {
                    Error.CompileWarning("Could not create context '" + context.Key + "', contexts must be sets of type 'context'.");
                    continue;
                }
                if (((IroSet)context.Value).SetType != "context")
                {
                    Error.CompileWarning("Could not create context '" + context.Key + "', values in the contexts array must be sets of type 'context'.");
                    continue;
                }

                pcd.Contexts.Add(ProcessContext(context.Key, (IroSet)context.Value, contextsSet));
            }

            //Use precompile data to process the given targets.
            var results = new List <CompileResult>();

            foreach (var target in targets)
            {
                results.Add(target.Compile(pcd));
            }

            return(results);
        }
Exemple #5
0
        /// <summary>
        /// Parses all the possible top level flags for Iro.
        /// </summary>
        private static void ParseTopLevelFlags(Dictionary <string, IroVariable> vars, ref IroPrecompileData pcd)
        {
            //Verify that the required keys exist.
            if (!vars.ContainsKey("name"))
            {
                Error.Compile("No 'name' variable defined to name the grammar.");
                return;
            }
            if (!vars.ContainsKey("file_extensions"))
            {
                Error.Compile("No 'file_extensions' variable defined to name the file extensions compatible with this grammar.");
                return;
            }
            if (vars["name"].Type != VariableType.Value)
            {
                Error.Compile("The 'name' variable must be a string.");
                return;
            }
            if (vars["file_extensions"].Type != VariableType.Array)
            {
                Error.Compile("The 'file_extensions' variable must define an array of file extensions (currently not an array).");
                return;
            }

            //Set name.
            pcd.Name = ((IroValue)vars["name"]).Value;

            //Set file extensions.
            IroList fileExts = (IroList)vars["file_extensions"];

            foreach (var ext in fileExts.Contents)
            {
                if (ext.Type != VariableType.Value)
                {
                    Error.Compile("All file extensions must be string values (detected type " + ext.Type.ToString() + " in array).");
                    return;
                }

                pcd.FileExtensions.Add(((IroValue)ext).Value);
            }

            //Parsing other top-level flags.
            //TEXTMATE UUID
            GetTopLevelProperty("textmate_uuid", ref pcd.UUID, ref vars);
            //DESCRIPTION
            GetTopLevelProperty("description", ref pcd.Description, ref vars);
            //COLOUR
            GetTopLevelProperty("color", ref pcd.Colour, ref vars);
            //BACKGROUND COLOUR
            GetTopLevelProperty("background_color", ref pcd.BackgroundColour, ref vars);
        }
Exemple #6
0
        /// <summary>
        /// Adds a PatternContextMember to the text, rather than a pattern that could possibly be any ContextMember.
        /// </summary>
        private void AddPatternRaw(ref StringBuilder text, PatternContextMember pattern, IroPrecompileData data)
        {
            //Get styles from the pattern.
            var styles = GetPatternStyles(pattern.Styles, data);

            //Is the amount of patterns equal to the amount of context groups?
            //Use a hack of replacing bracket groups with normal letters.
            if (!Compiler.GroupsMatch(pattern.Data, styles.Count))
            {
                Error.Compile("Mismatch between capture groups and number of styles for pattern with regex '" + pattern.Data + "'.");
                return;
            }

            //Add the initial match.
            text.AppendLine("<dict>");
            text.AppendLine("<key>match</key>");
            text.AppendLine("<string>" + pattern.Data + "</string>");

            //Only one style? Just use the 'name' property.
            if (pattern.Styles.Count == 1)
            {
                text.AppendLine("<key>name</key>");
                text.AppendLine("<string>" + styles[0].TextmateScope + "." + data.Name + "</string>");
            }
            else
            {
                //Multiple styles, define capture groups.
                text.AppendLine("<key>captures</key>");
                text.AppendLine("<dict>");
                for (int i = 0; i < styles.Count; i++)
                {
                    text.AppendLine("<key>" + (i + 1) + "</key>");
                    text.AppendLine("<dict>");
                    text.AppendLine("<key>name</key>");
                    text.AppendLine("<string>" + styles[i].TextmateScope + "." + data.Name + "</string>");
                    text.AppendLine("</dict>");
                }
                text.AppendLine("</dict>");
            }
            text.AppendLine("</dict>");
        }
Exemple #7
0
        /// <summary>
        /// Compiles a set of pre compile data into a textmate file.
        /// </summary>
        public CompileResult Compile(IroPrecompileData data)
        {
            var text = new StringBuilder();

            //Add pre-baked headers.
            text.AppendLine("<?xml  version=\"1.0\" encoding=\"UTF-8\"?>");
            text.AppendLine("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"   \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
            text.AppendLine("<plist version=\"1.0\">");
            text.AppendLine("<!-- Generated via. Iro4CLI -->");

            //Start the dictionary.
            text.AppendLine("<dict>");

            //Input the file types.
            if (data.FileExtensions == null || data.FileExtensions.Count == 0)
            {
                Error.Compile("No file extensions provided to map grammar against. Use 'file_extensions' to define them.");
                return(null);
            }
            text.AppendLine("<key>fileTypes</key>");
            text.AppendLine("<array>");
            foreach (var type in data.FileExtensions)
            {
                text.AppendLine("<string>" + type + "</string>");
            }
            text.AppendLine("</array>");

            //The name of the grammar.
            text.AppendLine("<key>name</key>");
            text.AppendLine("<string>" + data.Name + "</string>");


            //Pattern array, just including the main context here.
            if (data.Contexts.FindIndex(x => x.Name == "main") == -1)
            {
                Error.Compile("No entrypoint context named 'main' exists. You need to make a context named 'main' to start the grammar state at.");
                return(null);
            }
            text.AppendLine("<key>patterns</key>");
            text.AppendLine("<array>");
            text.AppendLine("<dict>");
            text.AppendLine("<key>include</key>");
            text.AppendLine("<string>#main</string>");
            text.AppendLine("</dict>");
            text.AppendLine("</array>");

            //Name of the source.
            text.AppendLine("<key>scopeName</key>");
            text.AppendLine("<string>source." + data.Name + "</string>");

            //UUID
            text.AppendLine("<key>uuid</key>");
            text.AppendLine("<string>" + data.UUID + "</string>");

            //Main repository for all contexts.
            text.AppendLine("<key>repository</key>");
            text.AppendLine("<dict>");

            //Define all the contexts inside the array.
            foreach (var context in data.Contexts)
            {
                //Add the pre-existing context.
                AddContext(ref text, context, data);
            }

            //Contexts done parsing, complete all queued contexts.
            foreach (var queued in pendingContexts)
            {
                AddContext(ref text, new IroContext(queued.Key)
                {
                    Members = queued.Value
                }, data);
            }
            pendingContexts = new Dictionary <string, List <ContextMember> >();

            //Close the textmate scopes.
            text.AppendLine("</dict>");
            text.AppendLine("</dict>");
            text.AppendLine("</plist>");

            return(new CompileResult()
            {
                GeneratedFile = FormatXml(text.ToString()),
                Target = Target.Textmate
            });
        }
Exemple #8
0
        /// <summary>
        /// Adds a InlinePushContextMember to the text.
        /// </summary>
        private void AddInlinePush(ref StringBuilder text, InlinePushContextMember pattern, IroPrecompileData data)
        {
            //Get styles from the pattern.
            var styles = GetPatternStyles(pattern.Styles, data);

            text.AppendLine("<dict>");

            //Patterns match up with context groups?
            if (!Compiler.GroupsMatch(pattern.Data, styles.Count))
            {
                Error.Compile("Mismatch between capture groups and number of styles for inline push with regex '" + pattern.Data + "'.");
                return;
            }

            //Begin capture regex.
            text.AppendLine("<key>begin</key>");
            text.AppendLine("<string>" + pattern.Data + "</string>");

            //Begin capture styles.
            text.AppendLine("<key>beginCaptures</key>");
            text.AppendLine("<dict>");
            for (int i = 0; i < styles.Count; i++)
            {
                text.AppendLine("<key>" + (i + 1) + "</key>");
                text.AppendLine("<dict>");
                text.AppendLine("<key>name</key>");
                text.AppendLine("<string>" + styles[i].TextmateScope + "." + data.Name + "</string>");
                text.AppendLine("</dict>");
            }
            text.AppendLine("</dict>");

            //Is a default style assigned?
            int defaultStyleIndex = pattern.Patterns.FindIndex(x => x.Type == ContextMemberType.DefaultStyle);

            if (defaultStyleIndex != -1)
            {
                //Are other patterns defined?
                if (pattern.Patterns.FindIndex(x => x.Type == ContextMemberType.Pattern) != -1)
                {
                    //Warn the user.
                    Error.CompileWarning("You cannot define unique patterns when a 'default_style' attribute is applied. Ignoring them.");
                }

                //Get the style out.
                var style = GetPatternStyles(new List <string>()
                {
                    pattern.Patterns[defaultStyleIndex].Data
                }, data);

                //Add default content name.
                text.AppendLine("<key>contentName</key>");
                text.AppendLine("<string>" + style[0].TextmateScope + "." + data.Name + "</string>");
            }
            else
            {
                //Actual patterns defined, not just default.
                //Begin patterns, capture all "pattern" sets and includes and queue them.
                text.AppendLine("<key>patterns</key>");
                text.AppendLine("<array>");

                //Include the queued context.
                if (pattern.Patterns.Count != 0)
                {
                    string helperName = "helper_" + ShortId.Generate(7);
                    text.AppendLine("<dict>");
                    text.AppendLine("<key>include</key>");
                    text.AppendLine("<string>#" + helperName + "</string>");
                    text.AppendLine("</dict>");

                    //Queue it.
                    QueueContext(helperName, pattern.Patterns);
                }
                text.AppendLine("</array>");
            }

            //Patterns done, pop condition & styles.
            var popStyles = GetPatternStyles(pattern.PopStyles, data);

            //Patterns match up with context groups?
            if (!Compiler.GroupsMatch(pattern.Data, styles.Count))
            {
                Error.Compile("Mismatch between capture groups and number of styles for pop with regex '" + pattern.PopData + "'.");
                return;
            }

            //Okay, add pop data.
            text.AppendLine("<key>end</key>");
            text.AppendLine("<string>" + pattern.PopData + "</string>");
            text.AppendLine("<key>endCaptures</key>");
            text.AppendLine("<dict>");
            for (int i = 0; i < popStyles.Count; i++)
            {
                text.AppendLine("<key>" + (i + 1) + "</key>");
                text.AppendLine("<dict>");
                text.AppendLine("<key>name</key>");
                text.AppendLine("<string>" + popStyles[i].TextmateScope + "." + data.Name + "</string>");
                text.AppendLine("</dict>");
            }
            text.AppendLine("</dict>");

            //Close the inline push.
            text.AppendLine("</dict>");
        }