diff --git a/Compiler/AceCompiler.cs b/Compiler/AceCompiler.cs index 42dc1ba..8b08d1b 100644 --- a/Compiler/AceCompiler.cs +++ b/Compiler/AceCompiler.cs @@ -26,7 +26,8 @@ public CompileResult Compile(IroPrecompileData data) //Add the header. text.AppendLine("/*"); text.AppendLine("* To try in Ace editor, copy and paste into the mode creator"); - text.AppendLine("*here : http://ace.c9.io/tool/mode_creator.html"); + text.AppendLine("* here: http://ace.c9.io/tool/mode_creator.html"); + text.AppendLine("* Generated using iro4cli!"); text.AppendLine("*/"); text.AppendLine(); text.AppendLine("define(function(require, exports, module) {"); @@ -119,7 +120,7 @@ private void AddMember(ContextMember member, string ctxName, ref StringBuilder t text.AppendLine("{"); text.AppendLine("\"token\": \"" + patternStyles[0].AceScope + "\","); //Replace normal '\' with '\\', since it's inside another string. - text.AppendLine("\"regex\": \"" + pattern.Data.Replace("\\", "\\\\") + "\""); + text.AppendLine("\"regex\": \"" + pattern.Data.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""); //Close pattern. text.AppendLine("},"); @@ -159,6 +160,24 @@ private void AddMember(ContextMember member, string ctxName, ref StringBuilder t text.AppendLine("},"); } + else if (member.Type == ContextMemberType.Push) + { + //Inline push pattern. + var push = ((PushContextMember)member); + var ilpStyles = GetPatternStyles(push.Styles, data); + + //Get the push data. + text.AppendLine("{"); + text.AppendLine("\"token\": \"" + ilpStyles[0].AceScope + "\","); + //Replace normal '\' with '\\', since it's inside another string. + text.AppendLine("\"regex\": \"" + push.Data.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\","); + + //Add push for target context. + text.AppendLine("\"push\": \"" + push.TargetContext + "\""); + + //Close pattern. + text.AppendLine("},"); + } else if (member.Type == ContextMemberType.Include) { //Include. diff --git a/Compiler/AtomCompiler.cs b/Compiler/AtomCompiler.cs index e85982e..a8ba14b 100644 --- a/Compiler/AtomCompiler.cs +++ b/Compiler/AtomCompiler.cs @@ -129,13 +129,6 @@ private void AddMember(ContextMember member, IroPrecompileData data, ref StringB var pattern = ((PatternContextMember)member); var styles = GetPatternStyles(pattern.Styles, data); - //Check if the groups match. - if (!Compiler.GroupsMatch(pattern.Data, styles.Count)) - { - Error.Compile("Amount of capture groups does not line up with the amount of assigned styles."); - return; - } - //Add to text. text.AppendLine("{"); //Make sure to replace backslashes and quotes. @@ -221,15 +214,58 @@ private void AddMember(ContextMember member, IroPrecompileData data, ref StringB //Patterns done, pop condition & styles. var popStyles = GetPatternStyles(ilp.PopStyles, data); - //Patterns match up with context groups? - if (!Compiler.GroupsMatch(ilp.PopData, popStyles.Count)) + //Okay, add pop data. + text.AppendLine("'end': '" + ilp.PopData.Replace("\\", "\\\\").Replace("'", "\\'") + "'"); + text.AppendLine("'endCaptures': {"); + for (int i = 0; i < popStyles.Count; i++) + { + text.AppendLine("'" + (i + 1) + "': {"); + text.AppendLine("'name': '" + popStyles[i].TextmateScope + "." + data.Name + "'"); + text.AppendLine("}"); + } + text.AppendLine("}"); + + //Close whole ILP. + text.AppendLine("}"); + } + else if (member.Type == ContextMemberType.Push) + { + //Push pattern. + var push = ((PushContextMember)member); + var styles = GetPatternStyles(push.Styles, data); + + //Add push styles. + text.AppendLine("{"); + text.AppendLine("'begin': '" + push.Data.Replace("\\", "\\\\").Replace("'", "\\'") + "'"); + text.AppendLine("'beginCaptures': {"); + for (int i=0; i x.Name == push.TargetContext); + if (targetCtx == null) { - Error.Compile("Mismatch between capture groups and number of styles for pop with regex '" + ilp.PopData + "'."); + Error.Compile($"Could not find target context '{push.TargetContext}' for push. Does it exist?"); return; } - //Okay, add pop data. - text.AppendLine("'end': '" + ilp.PopData.Replace("\\", "\\\\").Replace("'", "\\'") + "'"); + //Does a pop condition exist within this context? + var cond = targetCtx.Members.Find(x => x.Type == ContextMemberType.Pop); + if (cond == null) + { + Error.Compile($"No pop condition provided in pushed context '{push.TargetContext}'."); + return; + } + var popCondition = (PopContextMember)cond; + + //Patterns done, pop condition & styles. + var popStyles = GetPatternStyles(popCondition.Styles, data); + text.AppendLine("'end': '" + popCondition.Data.Replace("\\", "\\\\").Replace("'", "\\'") + "'"); text.AppendLine("'endCaptures': {"); for (int i = 0; i < popStyles.Count; i++) { @@ -239,7 +275,7 @@ private void AddMember(ContextMember member, IroPrecompileData data, ref StringB } text.AppendLine("}"); - //Close whole ILP. + //Close whole push. text.AppendLine("}"); } else if (member.Type == ContextMemberType.Include) diff --git a/Compiler/Compiler.cs b/Compiler/Compiler.cs index d7157b2..fa99c81 100644 --- a/Compiler/Compiler.cs +++ b/Compiler/Compiler.cs @@ -15,45 +15,6 @@ public static class Compiler //The variables currently being compiled. public static Dictionary Variables; - /// - /// Checks whether the amount of groups from a regex string is the same as expected. - /// - public static bool GroupsMatch(string data, int expectedGroups) - { - //Get groups out, ignoring escape chars. - int realGroups = 0; - bool ignoreNext = false, inCharSet = false; - for (int i=0; i /// Compiles a set of Algo variables given targets. /// @@ -322,10 +283,14 @@ private static IroContext ProcessContext(string contextName, IroSet context, Iro 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. + iroCtx.Members.Add(ParsePop((IroSet)value)); break; case "push": - //todo: add push rules + iroCtx.Members.Add(ParsePush((IroSet)value, contexts)); + break; + + //We have no idea what this is. + default: throw new NotImplementedException(); } } @@ -517,6 +482,10 @@ private static ContextMember ParseInlinePush(IroSet ilp, IroSet contexts) Error.Compile("Inline push attribute 'regex' must be a regex value."); return null; } + } else + { + //Just a normal regex, get out the string value. + regex = ((IroRegex)ilp["regex"]).StringValue; } if (!(ilp["styles"] is IroList)) { @@ -534,8 +503,7 @@ private static ContextMember ParseInlinePush(IroSet ilp, IroSet contexts) return null; } - //Get out the regex and style values. - regex = ((IroRegex)ilp["regex"]).StringValue; + //Get out the style values. List styles = new List(); foreach (var style in ((IroList)ilp["styles"])) { @@ -660,6 +628,171 @@ private static ContextMember ParseInlinePush(IroSet ilp, IroSet contexts) }; } + /// + /// Parses a single push context member in Iro. + /// + private static ContextMember ParsePush(IroSet push, IroSet contexts) + { + //Ensure the push has required fields 'regex', 'styles' and 'context'. + if (!push.ContainsKey("regex") || !push.ContainsKey("styles") + || !push.ContainsKey("context")) + { + Error.Compile("Required attribute is missing from push (must have members 'regex', 'styles', 'context')."); + return null; + } + + //Ensure types of required fields are correct. + string regex = null; + if (!(push["regex"] is IroRegex)) + { + //Is it a constant yet to be converted? + if ((push["regex"] is IroReference)) + { + //Attempt to get the constant. + IroVariable constant = GetConstant(((IroReference)push["regex"]).Value, VariableType.Regex); + if (constant is IroRegex) + { + regex = ((IroRegex)constant).StringValue; + } + else + { + regex = ((IroValue)constant).Value; + } + } + else + { + Error.Compile("Push attribute 'regex' must be a regex value."); + return null; + } + } + else + { + //Just a normal regex, get out the string value. + regex = ((IroRegex)push["regex"]).StringValue; + } + if (!(push["styles"] is IroList)) + { + Error.Compile("Push attribute 'styles' must be an array value."); + return null; + } + if (!(push["context"] is IroList) || ((IroList)push["context"]).Count() != 1) + { + Error.Compile("Push attribute 'context' must be an array value of length 1."); + return null; + } + + //Parse out the styles. + List styles = new List(); + foreach (var style in ((IroList)push["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); + } + + //Ensure that the target context value is of a valid type. + IroVariable context_var = ((IroList)push["context"]).ElementAt(0); + if (context_var.Type != VariableType.Value) + { + Error.Compile("Context items within 'push' must be a value type."); + return null; + } + + //Ensure that the target context exists within our context list. + var context_name = ((IroValue)context_var).Value; + if (!contexts.ContainsKey(context_name)) + { + Error.Compile($"Referenced context in push '{context_name}' not found in contexts list."); + return null; + } + + //Everything seems valid, create our push context! + return new PushContextMember() + { + Data = regex, + TargetContext = context_name, + Styles = styles, + Type = ContextMemberType.Push, + }; + } + + /// + /// Parses a single pop context member in Iro. + /// + private static ContextMember ParsePop(IroSet pop) + { + //Ensure the pop has required fields 'regex', 'styles'. + if (!pop.ContainsKey("regex") || !pop.ContainsKey("styles")) + { + Error.Compile("Required attribute is missing from pop (must have members 'regex', 'styles')."); + return null; + } + + //Ensure types of required fields are correct. + string regex = null; + if (!(pop["regex"] is IroRegex)) + { + //Is it a constant yet to be converted? + if ((pop["regex"] is IroReference)) + { + //Attempt to get the constant. + IroVariable constant = GetConstant(((IroReference)pop["regex"]).Value, VariableType.Regex); + if (constant is IroRegex) + { + regex = ((IroRegex)constant).StringValue; + } + else + { + regex = ((IroValue)constant).Value; + } + } + else + { + Error.Compile("Push attribute 'regex' must be a regex value."); + return null; + } + } + else + { + //Just a normal regex, get out the string value. + regex = ((IroRegex)pop["regex"]).StringValue; + } + if (!(pop["styles"] is IroList)) + { + Error.Compile("Push attribute 'styles' must be an array value."); + return null; + } + + //Parse out the styles. + List styles = new List(); + foreach (var style in ((IroList)pop["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 the pop. + return new PopContextMember() + { + Data = regex, + Styles = styles, + Type = ContextMemberType.Pop + }; + } + /// /// Finds sets recursively of type "pop" or "eol_pop". /// diff --git a/Compiler/PygmentsCompiler.cs b/Compiler/PygmentsCompiler.cs index 3561daf..b02d205 100644 --- a/Compiler/PygmentsCompiler.cs +++ b/Compiler/PygmentsCompiler.cs @@ -141,10 +141,10 @@ private void AddContextMember(string ctxName, ContextMember member, IroPrecompil regTxt += "(u'" + ilp.Data.Replace("\\", "\\\\") + "', bygroups("; //Get push styles out. - var pushStyles = GetPatternStyles(ilp.Styles, data); + var ilpStyles = GetPatternStyles(ilp.Styles, data); //Add and close bygroups scope. - foreach (var style in pushStyles) + foreach (var style in ilpStyles) { regTxt += style.PygmentsScope + ", "; } @@ -159,6 +159,27 @@ private void AddContextMember(string ctxName, ContextMember member, IroPrecompil text.AppendLine(regTxt); return; + //Push. + case ContextMemberType.Push: + var push = (PushContextMember)member; + regTxt += "(u'" + push.Data.Replace("\\", "\\\\") + "', bygroups("; + + //Get push styles out. + var pushStyles = GetPatternStyles(push.Styles, data); + + //Add and close bygroups scope. + foreach (var style in pushStyles) + { + regTxt += style.PygmentsScope + ", "; + } + regTxt = regTxt.TrimEnd(',', ' '); + regTxt += ")"; + + //Add the push target scope. + regTxt += ", '" + push.TargetContext + "'),"; + text.AppendLine(regTxt); + return; + //Include. case ContextMemberType.Include: //Get the context to include. diff --git a/Compiler/RougeCompiler.cs b/Compiler/RougeCompiler.cs index e0c0e22..f9298fe 100644 --- a/Compiler/RougeCompiler.cs +++ b/Compiler/RougeCompiler.cs @@ -12,7 +12,9 @@ namespace iro4cli public class RougeCompiler : ICompileTarget { //Contexts that are queued to generate. - public Dictionary, InlinePushContextMember> queuedContexts = new Dictionary, InlinePushContextMember>(); + public Dictionary, InlinePushContextMember> queuedIlpContexts = new Dictionary, InlinePushContextMember>(); + private List queuedContexts = new List(); + public List createdContexts = new List(); /// /// Turns Iro precompile data into a compiled Rouge target. @@ -23,6 +25,7 @@ public CompileResult Compile(IroPrecompileData data) //Add the coding header and modules. text.AppendLine("# -*- coding: utf-8 -*- #"); + text.AppendLine("# Generated with iro4cli! #"); text.AppendLine(); text.AppendLine("module Rouge"); text.TabIn(); @@ -53,12 +56,29 @@ public CompileResult Compile(IroPrecompileData data) } AddContext(mainCtx, "root", data, ref text); - //Add all the queued helpers. - while (queuedContexts.Count != 0) + while (queuedContexts.Count != 0 || queuedIlpContexts.Count != 0) { - var item = queuedContexts.ElementAt(0); - AddILPContext(item.Key.Item1, item.Key.Item2, item.Value, data, ref text); - queuedContexts.Remove(item.Key); + //Add all the queued contexts. + while (queuedContexts.Count != 0) + { + var ctx = data.Contexts.FirstOrDefault(x => x.Name == queuedContexts.ElementAt(0)); + if (ctx == null) + { + Error.Compile($"No context exists named '{queuedContexts.ElementAt(0)}' as referenced in a push context."); + return null; + } + AddContext(ctx, ctx.Name, data, ref text); + queuedContexts.Remove(ctx.Name); + } + + //Add all the queued helpers. + while (queuedIlpContexts.Count != 0) + { + var item = queuedIlpContexts.ElementAt(0); + AddILPContext(item.Key.Item1, item.Key.Item2, item.Value, data, ref text); + queuedIlpContexts.Remove(item.Key); + createdContexts.Add(item.Key.Item2); + } } //Close all the modules. @@ -149,18 +169,14 @@ private void AddContextMember(ContextMember member, string ctxName, IroPrecompil string ruleIlp = "rule /" + ilp.Data + "/"; //Get styles for pattern. Do they match up? - var pushStyles = GetPatternStyles(ilp.Styles, data); - string helperName = "helper_" + ShortId.Generate(7); + var ilpStyles = GetPatternStyles(ilp.Styles, data); + string helperName = ctxName + "_" + member.ID; - //Is the helper already made? - var madeHelper = queuedContexts.FirstOrDefault(x => x.Key.Item1 == ctxName && x.Value.Data == ilp.Data); - if (madeHelper.Key != null) - { - //Already made a helper, set the name. - helperName = madeHelper.Key.Item2; - } + //Is the helper already queued/created? + var madeHelper = queuedIlpContexts.Keys.Where(x => x.Item2 == helperName).ToList().Count > 0 + || createdContexts.Contains(helperName); - if (pushStyles.Count > 1) + if (ilpStyles.Count > 1) { //Grouped. ruleIlp += " do"; @@ -169,7 +185,7 @@ private void AddContextMember(ContextMember member, string ctxName, IroPrecompil ruleIlp = "groups "; - foreach (var style in pushStyles) + foreach (var style in ilpStyles) { ruleIlp += style.PygmentsScope.Replace(".", "::") + ", "; } @@ -184,10 +200,10 @@ private void AddContextMember(ContextMember member, string ctxName, IroPrecompil text.TabOut(); text.AppendLine("end"); } - else if (pushStyles.Count != 0) + else if (ilpStyles.Count != 0) { //Ungrouped. - ruleIlp += ", " + pushStyles[0].PygmentsScope.Replace(".", "::") + ", :" + helperName; + ruleIlp += ", " + ilpStyles[0].PygmentsScope.Replace(".", "::") + ", :" + helperName; text.AppendLine(ruleIlp); } else @@ -197,12 +213,58 @@ private void AddContextMember(ContextMember member, string ctxName, IroPrecompil } //Queue the push scope if not already pushed. - if (madeHelper.Key == null) + if (!madeHelper) { QueueILPScope(ctxName, helperName, ilp); } break; + case ContextMemberType.Push: + //Inline push pattern. + var push = (PushContextMember)member; + string rulePush = "rule /" + push.Data + "/"; + + //Get styles for pattern. Do they match up? + var pushStyles = GetPatternStyles(push.Styles, data); + if (pushStyles.Count > 1) + { + //Grouped. + rulePush += " do"; + text.AppendLine(rulePush); + text.TabIn(); + + ruleIlp = "groups "; + + foreach (var style in pushStyles) + { + ruleIlp += style.PygmentsScope.Replace(".", "::") + ", "; + } + + ruleIlp = ruleIlp.TrimEnd(' ', ','); + text.AppendLine(ruleIlp); + + //Add the push, queue the context for creation. + ruleIlp = "push :" + push.TargetContext; + QueuePushScope(push.TargetContext); + + //Tab out, end. + text.TabOut(); + text.AppendLine("end"); + } + else if (pushStyles.Count != 0) + { + //Ungrouped. + rulePush += ", " + pushStyles[0].PygmentsScope.Replace(".", "::") + ", :" + push.TargetContext; + QueuePushScope(push.TargetContext); + text.AppendLine(rulePush); + } + else + { + Error.Compile("No styles given for rule '" + push.Data + "'."); + return; + } + break; + case ContextMemberType.Include: //Get the context to include. @@ -229,7 +291,15 @@ private void AddContextMember(ContextMember member, string ctxName, IroPrecompil //Queues an inline push scope to be generated. private void QueueILPScope(string ctx, string helperName, InlinePushContextMember ilp) { - queuedContexts.Add(new Tuple(ctx, helperName), ilp); + queuedIlpContexts.Add(new Tuple(ctx, helperName), ilp); + } + + //Queues a single existing context to be generated. + private void QueuePushScope(string ctx) + { + if (queuedContexts.Contains(ctx)) + return; + queuedContexts.Add(ctx); } //Adds an inline push context member. @@ -312,7 +382,7 @@ private List GetPatternStyles(List styleNames, IroPrecompileDa styles.Add(data.Styles[index]); } - //Make sure all the patterns have textmate scopes. + //Make sure all the patterns have pygments scopes. if (styles.Where(x => x.PygmentsScope != null).Count() != styles.Count) { Error.Compile("One or more styles for a pattern does not have a Pygments scope defined."); diff --git a/Compiler/TextmateCompiler.cs b/Compiler/TextmateCompiler.cs index b356ca9..8276199 100644 --- a/Compiler/TextmateCompiler.cs +++ b/Compiler/TextmateCompiler.cs @@ -151,9 +151,10 @@ private void AddPattern(ref StringBuilder text, ContextMember pattern, IroPrecom AddInlinePush(ref text, (InlinePushContextMember)pattern, data); break; case ContextMemberType.Push: - throw new NotImplementedException(); + AddPush(ref text, (PushContextMember)pattern, data); + break; case ContextMemberType.Pop: - throw new NotImplementedException(); + return; //We don't directly add pops, they're processed by the "Push" rules. default: Error.CompileWarning("Failed to add pattern, unrecognized context member type '" + pattern.Type.ToString() + "'."); return; @@ -169,16 +170,9 @@ private void AddInlinePush(ref StringBuilder text, InlinePushContextMember patte var styles = GetPatternStyles(pattern.Styles, data); text.AppendLine(""); - //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("begin"); - text.AppendLine("" + pattern.Data + ""); + text.AppendLine("" + EscapeXMLElements(pattern.Data) + ""); //Begin capture styles. text.AppendLine("beginCaptures"); @@ -239,16 +233,85 @@ private void AddInlinePush(ref StringBuilder text, InlinePushContextMember patte //Patterns done, pop condition & styles. var popStyles = GetPatternStyles(pattern.PopStyles, data); - //Patterns match up with context groups? - if (!Compiler.GroupsMatch(pattern.Data, styles.Count)) + //Okay, add pop data. + text.AppendLine("end"); + text.AppendLine("" + EscapeXMLElements(pattern.PopData) + ""); + text.AppendLine("endCaptures"); + text.AppendLine(""); + for (int i = 0; i < popStyles.Count; i++) + { + text.AppendLine("" + (i + 1) + ""); + text.AppendLine(""); + text.AppendLine("name"); + text.AppendLine("" + popStyles[i].TextmateScope + "." + data.Name + ""); + text.AppendLine(""); + } + text.AppendLine(""); + + //Close the inline push. + text.AppendLine(""); + } + + /// + /// Adds a regular push to the Textmate output. + /// + private void AddPush(ref StringBuilder text, PushContextMember pattern, IroPrecompileData data) + { + //Get styles from the pattern. + var styles = GetPatternStyles(pattern.Styles, data); + text.AppendLine(""); + + //Begin capture regex. + text.AppendLine("begin"); + text.AppendLine("" + EscapeXMLElements(pattern.Data) + ""); + + //Begin capture styles. + text.AppendLine("beginCaptures"); + text.AppendLine(""); + for (int i=0; i" + (i + 1) + ""); + text.AppendLine(""); + text.AppendLine("name"); + text.AppendLine("" + styles[i].TextmateScope + "." + data.Name + ""); + text.AppendLine(""); + } + text.AppendLine(""); + + //Include the target context as the context patterns. + text.AppendLine("patterns"); + text.AppendLine(""); + text.AppendLine(""); + text.AppendLine("include"); + text.AppendLine($"{pattern.TargetContext}"); + text.AppendLine(""); + text.AppendLine(""); + + //Patterns done, attempt to fetch pop condition & styles. + var targetCtx = data.Contexts.Find(x => x.Name == pattern.TargetContext); + if (targetCtx == null) { - Error.Compile("Mismatch between capture groups and number of styles for pop with regex '" + pattern.PopData + "'."); + Error.Compile($"Could not find target context '{pattern.TargetContext}' for push. Does it exist?"); return; } - //Okay, add pop data. + //Does a pop condition exist within this context? + var cond = targetCtx.Members.Find(x => x.Type == ContextMemberType.Pop); + if (cond == null) + { + Error.Compile($"No pop condition provided in pushed context '{pattern.TargetContext}'."); + return; + } + var popCondition = (PopContextMember)cond; + + //Add the pop rule. text.AppendLine("end"); - text.AppendLine("" + pattern.PopData + ""); + text.AppendLine($"{EscapeXMLElements(popCondition.Data)}"); + + //Get pop styles to add them. + var popStyles = GetPatternStyles(popCondition.Styles, data); + + //Add pop styles. text.AppendLine("endCaptures"); text.AppendLine(""); for (int i = 0; i < popStyles.Count; i++) @@ -261,7 +324,7 @@ private void AddInlinePush(ref StringBuilder text, InlinePushContextMember patte } text.AppendLine(""); - //Close the inline push. + //Close the push. text.AppendLine(""); } @@ -281,18 +344,10 @@ private void AddPatternRaw(ref StringBuilder text, PatternContextMember pattern, //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(""); text.AppendLine("match"); - text.AppendLine("" + pattern.Data + ""); + text.AppendLine("" + EscapeXMLElements(pattern.Data) + ""); //Only one style? Just use the 'name' property. if (pattern.Styles.Count == 1) @@ -368,24 +423,27 @@ private string FormatXml(string xml) string indentedXml = doc.ToString(); var xmlBuilder = new StringBuilder(indentedXml); + //Fix greater than tokens within Regex. + indentedXml = UnescapeXMLElements(indentedXml); + //Try to format the Regex strings. - var matches = Regex.Matches(indentedXml, "[^\r\n]*"); - int currentDifferential = 0; - foreach (Match match in matches) - { - //Get the string out, XML format it. - string regex = Regex.Replace(match.Value, "|", ""); - regex = SecurityElement.Escape(regex); - regex = "" + regex + ""; - - //Insert new. - xmlBuilder.Remove(match.Index + currentDifferential, match.Length); - xmlBuilder.Insert(match.Index + currentDifferential, regex); - - //Update the differential. - //Previous inserts may have changed the index, so this variable compensates. - currentDifferential += regex.Length - match.Length; - } + // var matches = Regex.Matches(indentedXml, "[^\r\n]*"); + // int currentDifferential = 0; + // foreach (Match match in matches) + // { + // //Get the string out, XML format it. + // string regex = Regex.Replace(match.Value, "|", ""); + // regex = SecurityElement.Escape(regex); + // regex = "" + regex + ""; + + // //Insert new. + // xmlBuilder.Remove(match.Index + currentDifferential, match.Length); + // xmlBuilder.Insert(match.Index + currentDifferential, regex); + + // //Update the differential. + // //Previous inserts may have changed the index, so this variable compensates. + // currentDifferential += regex.Length - match.Length; + // } //Return the XML. return xmlBuilder.ToString(); @@ -398,6 +456,18 @@ private string FormatXml(string xml) } } + //Escapes any invalid XML elements. + private static string EscapeXMLElements(string original) + { + return original.Replace( "&","&").Replace("'","'").Replace( "\"", """).Replace(">",">").Replace( "<","<"); + } + + //Unescapes all XML escaped elements. + private static string UnescapeXMLElements(string escaped) + { + return escaped.Replace("'", "'").Replace(""", "\"").Replace(">", ">").Replace("<", "<").Replace("&", "&"); + } + /// /// Writes a VSCode extension to a given location. /// diff --git a/Data Structures/Compilation/IroContext.cs b/Data Structures/Compilation/IroContext.cs index e513ac9..cc9a2ac 100644 --- a/Data Structures/Compilation/IroContext.cs +++ b/Data Structures/Compilation/IroContext.cs @@ -20,6 +20,25 @@ public IroContext(string name) } } + /// + /// Represents a single push context member. + /// + public class PopContextMember : PatternContextMember + { + } + + /// + /// Represents a single push context member. + /// + public class PushContextMember : PatternContextMember + { + //The context we are pushing to. + public string TargetContext; + + //The styles associated with the push. + public List PushStyles = new List(); + } + /// /// Represents a single inline push context member. /// @@ -43,8 +62,17 @@ public class PatternContextMember : ContextMember /// public class ContextMember { + public int ID; public ContextMemberType Type; public string Data; + + private static int _curID = 0; + + public ContextMember() + { + ID = _curID; + _curID++; + } } /// diff --git a/build-release.sh b/build-release.sh index 56fb09d..d90ebb8 100755 --- a/build-release.sh +++ b/build-release.sh @@ -20,5 +20,6 @@ buildVariant linux-x64 buildVariant linux-musl-x64 buildVariant linux-arm64 buildVariant osx-x64 +buildVariant osx-arm64 echo -e "${GREEN}All builds completed. Exiting...${NC}" \ No newline at end of file