Skip to content

Commit 6c74814

Browse files
committed
memory leak fixes, improvements
1 parent 4234c06 commit 6c74814

21 files changed

+380
-340
lines changed

src/CascadiumCompiler.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,32 @@ public static CssStylesheet Parse(string xcss, CascadiumOptions? options = null)
2222
{
2323
CascadiumOptions _options = options ?? new CascadiumOptions();
2424

25+
CompilationContext context = new CompilationContext()
26+
{
27+
InputText = xcss,
28+
Options = _options
29+
};
30+
2531
//// strip comments and trim the input
2632
string sanitizedInput = Sanitizer.SanitizeInput(xcss);
2733

34+
var buffer = new TokenBuffer();
35+
2836
//// tokenizes the sanitized input, which is the lexical analyzer
2937
//// and convert the code into tokens
30-
TokenCollection resultTokens = new Tokenizer(sanitizedInput).Tokenize();
38+
new Tokenizer(sanitizedInput).Tokenize(buffer);
3139

3240
//// parses the produced tokens and produce an nested stylesheet from
3341
//// the token. this also applies the semantic and syntax checking
34-
NestedStylesheet nestedStylesheet = Parser.ParseSpreadsheet(resultTokens);
42+
NestedStylesheet nestedStylesheet = Parser.ParseSpreadsheet(buffer, context);
3543

3644
//// flatten the stylesheet, which removes the nesting and places all
3745
//// rules in the top level of the stylesheet.
3846
FlatStylesheet flattenStylesheet = Flattener.FlattenStylesheet(nestedStylesheet);
3947

4048
//// build the css body, assembling the flat rules into an valid
4149
//// css string
42-
CssStylesheet css = new Assembler(_options).AssemblyCss(flattenStylesheet, _options);
43-
css.Options = _options;
50+
CssStylesheet css = new Assembler(context).AssemblyCss(flattenStylesheet);
4451

4552
//// apply cascadium extensions
4653
if (_options.UseVarShortcut) ValueHandler.TransformVarShortcuts(css);

src/CascadiumException.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,19 @@ public class CascadiumException : Exception
99
public int Column { get; private set; }
1010
public string LineText { get; private set; }
1111

12-
internal CascadiumException(TokenDebugInfo snapshot, string message) : base(message)
12+
internal CascadiumException(TokenDebugInfo snapshot, string input, string message) : base(message)
1313
{
14-
Line = snapshot.Line;
15-
Column = snapshot.Column;
16-
LineText = snapshot.LineText;
14+
this.Line = snapshot.Line;
15+
this.Column = snapshot.Column;
16+
17+
string[] lines = input.Split('\n');
18+
if (lines.Length >= snapshot.Line)
19+
{
20+
this.LineText = lines[snapshot.Line - 1];
21+
}
22+
else
23+
{
24+
this.LineText = "";
25+
}
1726
}
1827
}

src/CascadiumLexer.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net8.0</TargetFramework>
55
<RootNamespace>Cascadium</RootNamespace>
66
<AssemblyName>Cascadium.Core</AssemblyName>
77
<ImplicitUsings>disable</ImplicitUsings>
@@ -21,9 +21,9 @@
2121
<PackageTags>css,scss,sass,less</PackageTags>
2222
<RepositoryType>git</RepositoryType>
2323

24-
<Version>0.6.1</Version>
25-
<AssemblyVersion>0.6.1</AssemblyVersion>
26-
<FileVersion>0.6.1</FileVersion>
24+
<Version>0.9.0</Version>
25+
<AssemblyVersion>0.9.0</AssemblyVersion>
26+
<FileVersion>0.9.0</FileVersion>
2727

2828
<NeutralLanguage>en</NeutralLanguage>
2929
<IncludeSymbols>True</IncludeSymbols>

src/CompilationContext.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Cascadium;
2+
3+
internal class CompilationContext
4+
{
5+
public required string InputText;
6+
public required CascadiumOptions Options;
7+
}

src/Compiler/Assembler.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,19 @@ namespace Cascadium.Compiler;
99

1010
class Assembler
1111
{
12-
public CascadiumOptions Options { get; set; }
12+
public CompilationContext Context { get; set; }
1313

14-
public Assembler(CascadiumOptions options)
14+
public Assembler(CompilationContext context)
1515
{
16-
Options = options;
16+
this.Context = context;
1717
}
1818

19-
public CssStylesheet AssemblyCss(FlatStylesheet flatStylesheet, CascadiumOptions options)
19+
public CssStylesheet AssemblyCss(FlatStylesheet flatStylesheet)
2020
{
21-
CssStylesheet result = new CssStylesheet();
21+
CssStylesheet result = new CssStylesheet()
22+
{
23+
Options = this.Context.Options
24+
};
2225
int ruleIndex = 0;
2326

2427
foreach (FlatRule rule in flatStylesheet.Rules)
@@ -35,15 +38,15 @@ public CssStylesheet AssemblyCss(FlatStylesheet flatStylesheet, CascadiumOptions
3538
cssRule = new CssRule()
3639
{
3740
_declarations = rule.Declarations,
38-
Selector = BuildCssSelector(rule.Selectors),
41+
Selector = this.BuildCssSelector(rule.Selectors),
3942
_order = ++ruleIndex
4043
};
4144
result._rules.Add(cssRule);
4245
}
4346
else
4447
{
4548
string? atRule = rule.PopAtRule();
46-
string selector = BuildCssSelector(rule.Selectors);
49+
string selector = this.BuildCssSelector(rule.Selectors);
4750

4851
cssRule = new CssRule()
4952
{
@@ -54,7 +57,7 @@ public CssStylesheet AssemblyCss(FlatStylesheet flatStylesheet, CascadiumOptions
5457

5558
if (atRule != null)
5659
{
57-
bool canMerge = options.Merge.HasFlag(MergeOption.AtRules)
60+
bool canMerge = this.Context.Options.Merge.HasFlag(MergeOption.AtRules)
5861
|| IsGroupAtRule(atRule);
5962
CssStylesheet atRuleStylesheet = result.GetOrCreateStylesheet(atRule, canMerge);
6063
atRuleStylesheet._rules.Add(cssRule);
@@ -68,12 +71,12 @@ public CssStylesheet AssemblyCss(FlatStylesheet flatStylesheet, CascadiumOptions
6871

6972
result._statements.AddRange(flatStylesheet.Statements);
7073

71-
if (options.Merge != MergeOption.None)
74+
if (this.Context.Options.Merge != MergeOption.None)
7275
{
73-
Merge(result, options);
76+
this.Merge(result, this.Context.Options);
7477
foreach (CssStylesheet subCss in result._stylesheets)
7578
{
76-
Merge(subCss, options);
79+
this.Merge(subCss, this.Context.Options);
7780
}
7881
}
7982

@@ -104,16 +107,16 @@ string BuildCssSelector(IList<string[]> selectors)
104107
}
105108
if (flatCount == 1)
106109
{
107-
return BuildCssSelector(selectors[0], Array.Empty<string>());
110+
return this.BuildCssSelector(selectors[0], Array.Empty<string>());
108111
}
109112
else
110113
{
111-
string carry = BuildCssSelector(selectors[0], Array.Empty<string>());
114+
string carry = this.BuildCssSelector(selectors[0], Array.Empty<string>());
112115
for (int i = 1; i < flatCount; i++)
113116
{
114117
string[] current = selectors[i];
115118
if (current.Length == 0) continue;
116-
carry = BuildCssSelector(current, Helper.SafeSplit(carry, ','));
119+
carry = this.BuildCssSelector(current, Helper.SafeSplit(carry, ','));
117120
}
118121
return carry;
119122
}
@@ -126,10 +129,10 @@ string BuildCssSelector(string[] currentSelectors, string[] parentSelectors)
126129
{
127130
foreach (string cSelector in currentSelectors)
128131
{
129-
string prepared = Helper.PrepareSelectorUnit(cSelector, Options.KeepNestingSpace, Options.Pretty);
132+
string prepared = Helper.PrepareSelectorUnit(cSelector, this.Context.Options.KeepNestingSpace, this.Context.Options.Pretty);
130133
sb.Append(prepared);
131134
sb.Append(',');
132-
if (Options.Pretty)
135+
if (this.Context.Options.Pretty)
133136
sb.Append(' ');
134137
}
135138
goto finish;
@@ -147,7 +150,7 @@ string BuildCssSelector(string[] currentSelectors, string[] parentSelectors)
147150
{
148151
sb.Append(b);
149152
s = c.Substring(1);
150-
if (!Options.KeepNestingSpace)
153+
if (!this.Context.Options.KeepNestingSpace)
151154
{
152155
s = s.TrimStart();
153156
}
@@ -168,17 +171,17 @@ string BuildCssSelector(string[] currentSelectors, string[] parentSelectors)
168171
s = c;
169172
}
170173

171-
s = Helper.PrepareSelectorUnit(s, Options.KeepNestingSpace, Options.Pretty);
174+
s = Helper.PrepareSelectorUnit(s, this.Context.Options.KeepNestingSpace, this.Context.Options.Pretty);
172175
sb.Append(s);
173176
sb.Append(',');
174-
if (Options.Pretty)
177+
if (this.Context.Options.Pretty)
175178
sb.Append(' ');
176179
}
177180
}
178181

179182
finish:
180183
if (sb.Length > 0) sb.Length--;
181-
if (sb.Length > 0 && Options.Pretty) sb.Length--;
184+
if (sb.Length > 0 && this.Context.Options.Pretty) sb.Length--;
182185
return sb.ToString();
183186
}
184187

src/Compiler/Parser.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Cascadium.Compiler;
66

77
class Parser
88
{
9-
public static NestedStylesheet ParseSpreadsheet(TokenCollection tokens)
9+
public static NestedStylesheet ParseSpreadsheet(TokenBuffer tokens, CompilationContext context)
1010
{
1111
NestedStylesheet spreadsheet = new NestedStylesheet();
1212

@@ -24,17 +24,17 @@ public static NestedStylesheet ParseSpreadsheet(TokenCollection tokens)
2424
else if (result.Type == TokenType.Em_Selector)
2525
{
2626
if (result.Content == "")
27-
throw new CascadiumException(result.DebugInfo, "empty selectors are not allowed");
27+
throw new CascadiumException(result.DebugInfo, context.InputText, "empty selectors are not allowed");
2828

2929
selectors.Add(result.Content);
3030
goto readRule__nextSelector;
3131
}
3232
else if (result.Type == TokenType.Em_RuleStart)
3333
{
3434
if (selectors.Count == 0)
35-
throw new CascadiumException(result.DebugInfo, "selector expected");
35+
throw new CascadiumException(result.DebugInfo, context.InputText, "selector expected");
3636

37-
ReadRule(tokens, spreadsheet, selectors.ToArray());
37+
ReadRule(tokens, context, spreadsheet, selectors.ToArray());
3838
selectors.Clear();
3939

4040
goto readRule__nextSelector;
@@ -50,15 +50,15 @@ public static NestedStylesheet ParseSpreadsheet(TokenCollection tokens)
5050
}
5151
else
5252
{
53-
throw new CascadiumException(result.DebugInfo, "unexpected token");
53+
throw new CascadiumException(result.DebugInfo, context.InputText, "unexpected token");
5454
}
5555
}
5656

5757
finish:
5858
return spreadsheet;
5959
}
6060

61-
static void ReadRule(TokenCollection tokens, IRuleContainer container, string[] externSelectors)
61+
static void ReadRule(TokenBuffer tokens, CompilationContext context, IRuleContainer container, string[] externSelectors)
6262
{
6363
int ruleIndex = 0;
6464
List<string> buildingSelectors = new List<string>();
@@ -75,10 +75,10 @@ static void ReadRule(TokenCollection tokens, IRuleContainer container, string[]
7575
else if (result.Type == TokenType.Em_RuleStart)
7676
{
7777
if (buildingSelectors.Count == 0)
78-
throw new CascadiumException(result.DebugInfo, "selector expected");
78+
throw new CascadiumException(result.DebugInfo, context.InputText, "selector expected");
7979

8080
ruleIndex++;
81-
ReadRule(tokens, buildingRule, buildingSelectors.ToArray());
81+
ReadRule(tokens, context, buildingRule, buildingSelectors.ToArray());
8282

8383
buildingSelectors.Clear();
8484

@@ -89,7 +89,8 @@ static void ReadRule(TokenCollection tokens, IRuleContainer container, string[]
8989
tokens.Read(out Token valueToken);
9090

9191
if (valueToken.Type != TokenType.Em_PropertyValue)
92-
throw new CascadiumException(tokens.Last.DebugInfo, "property value expected");
92+
throw new CascadiumException(tokens.Last.DebugInfo, context.InputText, "property value expected");
93+
9394
if (string.IsNullOrWhiteSpace(valueToken.Content))
9495
goto readRule__nextItem; // skip empty declarations
9596

@@ -99,16 +100,16 @@ static void ReadRule(TokenCollection tokens, IRuleContainer container, string[]
99100
else if (result.Type == TokenType.Em_Selector)
100101
{
101102
if (result.Content == "")
102-
throw new CascadiumException(result.DebugInfo, "empty selectors are not allowed");
103+
throw new CascadiumException(result.DebugInfo, context.InputText, "empty selectors are not allowed");
103104
if (IsSelectorInvalidRuleset(result.Content))
104-
throw new CascadiumException(result.DebugInfo, "; expected");
105+
throw new CascadiumException(result.DebugInfo, context.InputText, "; expected");
105106

106107
buildingSelectors.Add(result.Content);
107108
goto readRule__nextItem;
108109
}
109110
else
110111
{
111-
throw new CascadiumException(result.DebugInfo, "unexpected token");
112+
throw new CascadiumException(result.DebugInfo, context.InputText, "unexpected token");
112113
}
113114
}
114115

0 commit comments

Comments
 (0)