From 338b4ba23c94b8c03790a9c809dd3ff8331a0d05 Mon Sep 17 00:00:00 2001 From: Marcin Golebiowski Date: Sun, 29 Aug 2021 14:43:32 +0200 Subject: [PATCH 1/3] Improve case sensitivity settings - add option to configure subcircuit names and improve handling of functions inside expressions, update packages --- .../Common/CaseSensitivityTests.cs | 80 +++++++++++++++++++ .../SpiceSharpParser.IntegrationTests.csproj | 8 +- .../SpiceSharpParser.Tests.csproj | 6 +- .../SpiceNetlistCaseSensitivitySettings.cs | 5 ++ .../Netlist/Spice/Context/IReadingContext.cs | 4 +- .../Netlist/Spice/Context/ReadingContext.cs | 16 ++-- .../Components/SubCircuitGenerator.cs | 17 ++-- .../Readers/SubcircuitDefinitionReader.cs | 2 +- .../Netlist/Spice/SpiceNetlistReader.cs | 10 +++ src/SpiceSharpParser/SpiceSharpParser.csproj | 4 +- 10 files changed, 124 insertions(+), 28 deletions(-) diff --git a/src/SpiceSharpParser.IntegrationTests/Common/CaseSensitivityTests.cs b/src/SpiceSharpParser.IntegrationTests/Common/CaseSensitivityTests.cs index 87c65530..a13f145d 100644 --- a/src/SpiceSharpParser.IntegrationTests/Common/CaseSensitivityTests.cs +++ b/src/SpiceSharpParser.IntegrationTests/Common/CaseSensitivityTests.cs @@ -1,4 +1,8 @@ +using SpiceSharpParser.Common; +using SpiceSharpParser.ModelReaders.Netlist.Spice; using System; +using System.IO; +using System.Text; using Xunit; namespace SpiceSharpParser.IntegrationTests.Common @@ -54,6 +58,35 @@ public void FunctionNamePositive() spiceModel.Simulations[0].Run(spiceModel.Circuit); } + [Fact] + public void FunctionNamePositiveTest2() + { + var parser = new SpiceNetlistParser(); + + parser.Settings.Lexing.HasTitle = true; + parser.Settings.Parsing.IsEndRequired = true; + + var text = string.Join( + Environment.NewLine, + "CaseSensitivity", + "R1 0 1 1", + "V1 0 1 {PWR(V(2),2)}", + "V2 0 2 10", + ".OP", + ".End"); + + var parseResult = parser.ParseNetlist(text); + var reader = new SpiceSharpReader(); + reader.Settings.CaseSensitivity.IsFunctionNameCaseSensitive = false; + + var spiceModel = reader.Read(parseResult.FinalModel); + + Assert.NotNull(parseResult); + Assert.False(parseResult.ValidationResult.HasError); + Assert.False(parseResult.ValidationResult.HasWarning); + spiceModel.Simulations[0].Run(spiceModel.Circuit); + } + [Fact] public void When_DistributionNameNotSensitive_Expect_NoException() { @@ -542,5 +575,52 @@ public void EntityParameterPositive3() Assert.True(EqualsWithTol(export, references)); } + + [Fact] + public void SubcircuitPositive() + { + var text = string.Join(Environment.NewLine, "Subcircuit - Case", + "V1 IN 0 4.0", + "X1 IN OUT resistor", + "RX OUT 0 1", + ".SUBCKT RESISTOR input output params: R=1", + "R1 input output {R}", + ".ENDS RESISTOR", + ".OP", + ".SAVE V(OUT)", + ".END"); + var parser = new SpiceNetlistParser(); + var netlist = parser.ParseNetlist(text); + + var spiceSharpSettings = new SpiceNetlistReaderSettings(new SpiceNetlistCaseSensitivitySettings() { IsSubcircuitNameCaseSensitive = false }, () => parser.Settings.WorkingDirectory, Encoding.Default); + var spiceSharpReader = new SpiceNetlistReader(spiceSharpSettings); + + var model = spiceSharpReader.Read(netlist.FinalModel); + Assert.False(model.ValidationResult.HasError); + } + + [Fact] + public void SubcircuitPositive2() + { + var text = string.Join(Environment.NewLine, "Subcircuit - Case", + "V1 IN 0 4.0", + "X1 IN OUT resistor", + "RX OUT 0 1", + ".SUBCKT RESISTOR input output params: R=1", + "R1 input output {R}", + ".ENDS RESISTOR", + ".OP", + ".SAVE V(OUT)", + ".END"); + + var parser = new SpiceNetlistParser(); + var netlist = parser.ParseNetlist(text); + + var spiceSharpSettings = new SpiceNetlistReaderSettings(new SpiceNetlistCaseSensitivitySettings() { IsSubcircuitNameCaseSensitive = true }, () => parser.Settings.WorkingDirectory, Encoding.Default); + var spiceSharpReader = new SpiceNetlistReader(spiceSharpSettings); + + var model = spiceSharpReader.Read(netlist.FinalModel); + Assert.True(model.ValidationResult.HasError); + } } } \ No newline at end of file diff --git a/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj b/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj index 04eedb1b..35309758 100644 --- a/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj +++ b/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj @@ -16,14 +16,14 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + all diff --git a/src/SpiceSharpParser.Tests/SpiceSharpParser.Tests.csproj b/src/SpiceSharpParser.Tests/SpiceSharpParser.Tests.csproj index 0bdb77cb..a6fee99c 100644 --- a/src/SpiceSharpParser.Tests/SpiceSharpParser.Tests.csproj +++ b/src/SpiceSharpParser.Tests/SpiceSharpParser.Tests.csproj @@ -14,14 +14,14 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + all runtime; build; native; contentfiles; analyzers diff --git a/src/SpiceSharpParser/Common/SpiceNetlistCaseSensitivitySettings.cs b/src/SpiceSharpParser/Common/SpiceNetlistCaseSensitivitySettings.cs index e2df39ac..9088789c 100644 --- a/src/SpiceSharpParser/Common/SpiceNetlistCaseSensitivitySettings.cs +++ b/src/SpiceSharpParser/Common/SpiceNetlistCaseSensitivitySettings.cs @@ -44,5 +44,10 @@ public class SpiceNetlistCaseSensitivitySettings /// Gets or sets a value indicating whether expression names are case-sensitive. /// public bool IsExpressionNameCaseSensitive { get; set; } = false; + + /// + /// Gets or sets a value indicating whether subcircuit names are case-sensitive. + /// + public bool IsSubcircuitNameCaseSensitive { get; set; } = false; } } \ No newline at end of file diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/IReadingContext.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/IReadingContext.cs index 6903e678..6fdd98d3 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/IReadingContext.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/IReadingContext.cs @@ -44,9 +44,9 @@ public interface IReadingContext ICollection Children { get; } /// - /// Gets the list of available subcircuit for the context. + /// Gets the dictionary of available subcircuit for the context. /// - ICollection AvailableSubcircuits { get; } + Dictionary AvailableSubcircuits { get; } /// /// Gets the list of available subcircuit for the context. diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/ReadingContext.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/ReadingContext.cs index 5f316a40..87bbab95 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/ReadingContext.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/ReadingContext.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using SpiceSharp; using SpiceSharp.Components; using SpiceSharp.Entities; @@ -17,7 +16,6 @@ using SpiceSharpParser.ModelReaders.Netlist.Spice.Readers.Controls.Simulations.Configurations; using SpiceSharpParser.Models.Netlist.Spice.Objects; using SpiceSharpParser.Models.Netlist.Spice.Objects.Parameters; -using SpiceSharpParser.Parsers.Expression; namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Context { @@ -61,9 +59,9 @@ public ReadingContext( Children = new List(); StatementsReader = statementsReader; WaveformReader = waveformReader; + ReaderSettings = readerSettings; AvailableSubcircuits = CreateAvailableSubcircuitsCollection(); AvailableSubcircuitDefinitions = CreateAvailableSubcircuitDefinitions(); - ReaderSettings = readerSettings; Exporters = exporters; ContextEntities = new Circuit(new EntityCollection(StringComparerProvider.Get(readerSettings.CaseSensitivity.IsEntityNamesCaseSensitive))); SimulationConfiguration = simulationConfiguration; @@ -108,7 +106,7 @@ public ReadingContext( /// /// Gets available subcircuits in context. /// - public ICollection AvailableSubcircuits { get; } + public Dictionary AvailableSubcircuits { get; } public Dictionary AvailableSubcircuitDefinitions { get; } @@ -389,15 +387,15 @@ public ExpressionResolver CreateExpressionResolver(Simulation simulation) return parser; } - protected ICollection CreateAvailableSubcircuitsCollection() + protected Dictionary CreateAvailableSubcircuitsCollection() { if (Parent != null) { - return new List(Parent.AvailableSubcircuits); + return new Dictionary(Parent.AvailableSubcircuits, StringComparerProvider.Get(ReaderSettings.CaseSensitivity.IsSubcircuitNameCaseSensitive)); } else { - return new List(); + return new Dictionary(StringComparerProvider.Get(ReaderSettings.CaseSensitivity.IsSubcircuitNameCaseSensitive)); } } @@ -405,11 +403,11 @@ protected Dictionary CreateAvailableSubcircuitDefi { if (Parent != null) { - return new Dictionary(Parent.AvailableSubcircuitDefinitions); + return new Dictionary(Parent.AvailableSubcircuitDefinitions, StringComparerProvider.Get(ReaderSettings.CaseSensitivity.IsSubcircuitNameCaseSensitive)); } else { - return new Dictionary(); + return new Dictionary(StringComparerProvider.Get(ReaderSettings.CaseSensitivity.IsSubcircuitNameCaseSensitive)); } } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/SubCircuitGenerator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/SubCircuitGenerator.cs index a004ad0d..60e3cc8e 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/SubCircuitGenerator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/SubCircuitGenerator.cs @@ -188,17 +188,20 @@ private SubCircuit FindSubcircuitDefinition(ParameterCollection parameters, IRea } string subCircuitDefinitionName = parameters.Get(parameters.Count - skipCount - 1).Value; - var result = context.AvailableSubcircuits.ToList().Find(subCkt => subCkt.Name == subCircuitDefinitionName); - if (result == null) + if (context.AvailableSubcircuits.TryGetValue(subCircuitDefinitionName, out var result)) { - context.Result.ValidationResult.AddError( - ValidationEntrySource.Reader, - $"Could not find '{subCircuitDefinitionName}' subcircuit", - parameters.LineInfo); + if (result == null) + { + context.Result.ValidationResult.AddError( + ValidationEntrySource.Reader, + $"Could not find '{subCircuitDefinitionName}' subcircuit", + parameters.LineInfo); + } + return result; } - return result; + return null; } private List GetPinNames(ParameterCollection parameters) diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/SubcircuitDefinitionReader.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/SubcircuitDefinitionReader.cs index 85d2c352..9619af03 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/SubcircuitDefinitionReader.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/SubcircuitDefinitionReader.cs @@ -26,7 +26,7 @@ public override void Read(SubCircuit statement, IReadingContext context) throw new ArgumentNullException(nameof(context)); } - context.AvailableSubcircuits.Add(statement); + context.AvailableSubcircuits[statement.Name] = statement; } } } \ No newline at end of file diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/SpiceNetlistReader.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/SpiceNetlistReader.cs index c4442812..7d5f215d 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/SpiceNetlistReader.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/SpiceNetlistReader.cs @@ -1,5 +1,8 @@ using SpiceSharp; using SpiceSharp.Entities; +using SpiceSharpBehavioral.Builders.Direct; +using SpiceSharpBehavioral.Builders.Functions; +using SpiceSharpBehavioral.Parsers.Nodes; using SpiceSharpParser.Common; using SpiceSharpParser.Common.Evaluation; using SpiceSharpParser.Common.Mathematics.Probability; @@ -53,6 +56,13 @@ public SpiceSharpModel Read(SpiceNetlist netlist) // Set the separator. Utility.Separator = Settings.Separator; + // Set functions case-sensitivity + ComplexBuilderHelper.RemapFunctions(StringComparerProvider.Get(Settings.CaseSensitivity.IsFunctionNameCaseSensitive)); + ComplexFunctionBuilderHelper.RemapFunctions(StringComparerProvider.Get(Settings.CaseSensitivity.IsFunctionNameCaseSensitive)); + RealBuilderHelper.RemapFunctions(StringComparerProvider.Get(Settings.CaseSensitivity.IsFunctionNameCaseSensitive)); + RealFunctionBuilderHelper.RemapFunctions(StringComparerProvider.Get(Settings.CaseSensitivity.IsFunctionNameCaseSensitive)); + DerivativesHelper.RemapFunctions(StringComparerProvider.Get(Settings.CaseSensitivity.IsFunctionNameCaseSensitive)); + // Get reading context var nodeNameGenerator = new MainCircuitNodeNameGenerator( new[] { "0" }, diff --git a/src/SpiceSharpParser/SpiceSharpParser.csproj b/src/SpiceSharpParser/SpiceSharpParser.csproj index 213866cd..2e133c40 100644 --- a/src/SpiceSharpParser/SpiceSharpParser.csproj +++ b/src/SpiceSharpParser/SpiceSharpParser.csproj @@ -35,9 +35,9 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive From a0ee498b6aa16a275cd75e8739782bcca027da55 Mon Sep 17 00:00:00 2001 From: Marcin Golebiowski Date: Sun, 29 Aug 2021 14:45:00 +0200 Subject: [PATCH 2/3] Update version --- src/SpiceSharpParser/SpiceSharpParser.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SpiceSharpParser/SpiceSharpParser.csproj b/src/SpiceSharpParser/SpiceSharpParser.csproj index 2e133c40..48ea72fe 100644 --- a/src/SpiceSharpParser/SpiceSharpParser.csproj +++ b/src/SpiceSharpParser/SpiceSharpParser.csproj @@ -22,7 +22,7 @@ MIT latest - 3.1.1 + 3.1.2 From f3306a14ea25511a668e580e94bbf99eab0e93f1 Mon Sep 17 00:00:00 2001 From: Marcin Golebiowski Date: Sun, 29 Aug 2021 14:57:28 +0200 Subject: [PATCH 3/3] Update packages --- .../SpiceSharpParser.CodeAnalysis.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SpiceSharpParser.CodeAnalysis/SpiceSharpParser.CodeAnalysis.csproj b/src/SpiceSharpParser.CodeAnalysis/SpiceSharpParser.CodeAnalysis.csproj index 8807477d..59fe75ac 100644 --- a/src/SpiceSharpParser.CodeAnalysis/SpiceSharpParser.CodeAnalysis.csproj +++ b/src/SpiceSharpParser.CodeAnalysis/SpiceSharpParser.CodeAnalysis.csproj @@ -21,9 +21,9 @@ - + - + all runtime; build; native; contentfiles; analyzers