From 514f77e26d3f6b92002151c38fe8439bc67857ac Mon Sep 17 00:00:00 2001 From: Mads Kristensen Date: Mon, 3 Jan 2022 15:25:53 -0800 Subject: [PATCH] Strengthened parser from testing against hundreds of pkgdef files [release] --- src/Language/EditorFeatures.cs | 1 + src/Parser/DocumentParser.cs | 15 ++++++++++++--- src/Parser/DocumentValidator.cs | 26 ++++++++++++++++---------- src/Parser/ItemType.cs | 1 + src/Parser/PredefinedVariables.cs | 2 ++ test/ParseTest.cs | 2 +- 6 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/Language/EditorFeatures.cs b/src/Language/EditorFeatures.cs index ab4cc6c..b43a718 100644 --- a/src/Language/EditorFeatures.cs +++ b/src/Language/EditorFeatures.cs @@ -22,6 +22,7 @@ public class SyntaxHighligting : TokenClassificationTaggerBase { ItemType.Comment, PredefinedClassificationTypeNames.Comment }, { ItemType.Reference, PredefinedClassificationTypeNames.SymbolReference }, { ItemType.Operator, PredefinedClassificationTypeNames.Operator }, + { ItemType.Preprocessor, PredefinedClassificationTypeNames.PreprocessorKeyword }, }; } diff --git a/src/Parser/DocumentParser.cs b/src/Parser/DocumentParser.cs index f167527..2ccd366 100644 --- a/src/Parser/DocumentParser.cs +++ b/src/Parser/DocumentParser.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; namespace PkgdefLanguage { public partial class Document { - private static readonly Regex _regexProperty = new(@"^(?.+)(\s)*(?=)\s*(?(dword:[\d].+|"".+))", RegexOptions.Compiled); + private static readonly Regex _regexProperty = new(@"^(?""[^""]+""|@)(\s)*(?=)\s*(?((dword:|hex).+|"".+))", RegexOptions.Compiled); private static readonly Regex _regexRef = new(@"\$[\w]+\$?", RegexOptions.Compiled); public void Parse() @@ -29,7 +30,7 @@ public void Parse() private IEnumerable ParseLine(int start, string line, List tokens) { - var trimmedLine = line.TrimEnd(); + var trimmedLine = line.Trim(); List items = new(); // Comment @@ -37,6 +38,11 @@ private IEnumerable ParseLine(int start, string line, List { items.Add(ToParseItem(line, start, ItemType.Comment, false)); } + // Preprocessor + else if (trimmedLine.StartsWith("#include")) + { + items.Add(ToParseItem(line, start, ItemType.Preprocessor, false)); + } // Registry key else if (trimmedLine.StartsWith("[", StringComparison.Ordinal)) { @@ -66,7 +72,10 @@ private IEnumerable ParseLine(int start, string line, List // Unknown else if (trimmedLine.Length > 0) { - items.Add(new ParseItem(start, line, this, ItemType.Unknown)); + // Check for line splits which is a line ending with a backslash + var lineSplit = tokens.LastOrDefault()?.Text.TrimEnd().EndsWith("\\") == true; + ItemType type = lineSplit ? tokens.Last().Type : ItemType.Unknown; + items.Add(new ParseItem(start, line, this, type)); } return items; diff --git a/src/Parser/DocumentValidator.cs b/src/Parser/DocumentValidator.cs index 279cb70..99af169 100644 --- a/src/Parser/DocumentValidator.cs +++ b/src/Parser/DocumentValidator.cs @@ -48,10 +48,10 @@ private void ValidateDocument() { AddError(item, Errors.PL002); } - else if (trimmedText.Contains("/") && !trimmedText.Contains("\\/")) - { - AddError(item, Errors.PL003); - } + //else if (trimmedText.Contains("/") && !trimmedText.Contains("\\/")) + //{ + // AddError(item, Errors.PL003); + //} var index = Items.IndexOf(item); if (Items.Take(index).Any(i => i.Type == ItemType.RegistryKey && item.Text == i.Text)) @@ -93,14 +93,20 @@ private void ValidateDocument() { var refTrim = reference.Text.Trim(); - if (!refTrim.EndsWith("$")) - { - AddError(reference, Errors.PL007); - } - else if (!PredefinedVariables.Variables.Any(v => v.Key.Equals(refTrim.Trim('$'), StringComparison.OrdinalIgnoreCase))) + //if (!refTrim.EndsWith("$")) + //{ + // AddError(reference, Errors.PL007); + //} + //else + //{ + if (refTrim.EndsWith("$")) { - AddError(reference, Errors.PL006.WithFormat(refTrim)); + if (!PredefinedVariables.Variables.Any(v => v.Key.Equals(refTrim.Trim('$'), StringComparison.OrdinalIgnoreCase))) + { + AddError(reference, Errors.PL006.WithFormat(refTrim)); + } } + //} } } } diff --git a/src/Parser/ItemType.cs b/src/Parser/ItemType.cs index 06e8f69..23036d6 100644 --- a/src/Parser/ItemType.cs +++ b/src/Parser/ItemType.cs @@ -11,5 +11,6 @@ public enum ItemType Unknown, Entry, Property, + Preprocessor } } diff --git a/src/Parser/PredefinedVariables.cs b/src/Parser/PredefinedVariables.cs index 278060a..22e0ff3 100644 --- a/src/Parser/PredefinedVariables.cs +++ b/src/Parser/PredefinedVariables.cs @@ -7,9 +7,11 @@ internal sealed class PredefinedVariables public static Dictionary Variables = new() { { "AppDataLocalFolder", "The subfolder under %LOCALAPPDATA% for this application." }, + { "ApplicationExtensionsFolder", "n/a" }, { "AppName", "The qualified name of the application that is passed to the AppEnv.dll entry points. The qualified name consists of the application name, an underscore, and the class identifier (CLSID of the application automation object, which is also recorded as the value of the ThisVersionDTECLSID setting in the project .pkgdef file." }, { "BaseInstallDir", "The full path of the location where Visual Studio was installed." }, { "CommonFiles", "The value of the %CommonProgramFiles% environment variable." }, + { "Initialization", "n/a" }, { "MyDocuments", "The full path of the My Documents folder of the current user." }, { "PackageFolder", "The full path of the directory that contains the package assembly files for the application." }, { "ProgramFiles", "The value of the %ProgramFiles% environment variable." }, diff --git a/test/ParseTest.cs b/test/ParseTest.cs index 5887cce..bf59596 100644 --- a/test/ParseTest.cs +++ b/test/ParseTest.cs @@ -76,7 +76,7 @@ public async Task Comment() { var lines = new[] { "; comment\r\n", "\r\n", - "; comment" + ";comment" }; var doc = Document.FromLines(lines);