1 //
2 // Copyright (c) 2010-2023 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Linq;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.PlatformDescription;
11 using Antmicro.Renode.PlatformDescription.Syntax;
12 using NUnit.Framework;
13 using Sprache;
14 using System.Text;
15 
16 namespace Antmicro.Renode.UnitTests.PlatformDescription
17 {
18     [TestFixture]
19     public class ParserTests
20     {
21         [Test]
ShouldParseEmptyFile()22         public void ShouldParseEmptyFile()
23         {
24             var source = string.Empty;
25 
26             var result = Grammar.Description(GetInputFromString(source));
27             Assert.IsTrue(result.WasSuccessful, result.ToString());
28         }
29 
30         [Test]
ShouldParseUsingEntry()31         public void ShouldParseUsingEntry()
32         {
33             var source = @"
34 using ""file.pl8""
35 using ""other_file.pl8""";
36 
37             var input = GetInputFromString(source);
38             var result = Grammar.Description(input);
39             Assert.IsTrue(result.WasSuccessful, result.ToString());
40 
41             var usingEntries = result.Value.Usings.Select(x => x.Path.Value);
42             CollectionAssert.AreEquivalent(new[] { "file.pl8", "other_file.pl8" }, usingEntries);
43         }
44 
45         [Test]
ShouldParseSimpleEntry()46         public void ShouldParseSimpleEntry()
47         {
48             var source = @"
49 uart: UART";
50             var result = Grammar.Description(GetInputFromString(source));
51             Assert.IsTrue(result.WasSuccessful, result.ToString());
52 
53             var entry = result.Value.Entries.Single();
54             Assert.AreEqual("uart", entry.VariableName);
55             Assert.AreEqual("UART", (string)entry.Type);
56         }
57 
58         [Test]
ShouldParseEntryWithSimpleRegistrationInfo()59         public void ShouldParseEntryWithSimpleRegistrationInfo()
60         {
61             var source = @"
62 uart: @ sysbus";
63             var result = Grammar.Description(GetInputFromString(source));
64             Assert.IsTrue(result.WasSuccessful, result.ToString());
65 
66             var entry = result.Value.Entries.Single();
67             Assert.AreEqual("uart", entry.VariableName);
68             Assert.IsNull(entry.Type);
69             Assert.AreEqual("sysbus", entry.RegistrationInfos.Single().Register.Value);
70             Assert.IsNull(entry.RegistrationInfos.Single().RegistrationPoint);
71         }
72 
73         [Test]
ShouldParseEntryWithRangeRegistrationPoint()74         public void ShouldParseEntryWithRangeRegistrationPoint()
75         {
76             var source = @"
77 uart: @ sysbus <0x2000A000, +0x1000>";
78             var result = Grammar.Description(GetInputFromString(source));
79             Assert.IsTrue(result.WasSuccessful, result.ToString());
80 
81             var entry = result.Value.Entries.Single();
82             Assert.AreEqual("uart", entry.VariableName);
83             Assert.IsNull(entry.Type);
84             Assert.AreEqual("sysbus", entry.RegistrationInfos.Single().Register.Value);
85             Assert.AreEqual(0x2000A000.By(0x1000), ((RangeValue)entry.RegistrationInfos.Single().RegistrationPoint).ToRange());
86         }
87 
88         [Test]
ShouldParseEntryWithStringRegistrationPoint()89         public void ShouldParseEntryWithStringRegistrationPoint()
90         {
91             var source = @"
92 uart: @ sysbus ""something""";
93             var result = Grammar.Description(GetInputFromString(source));
94             Assert.IsTrue(result.WasSuccessful, result.ToString());
95 
96             var entry = result.Value.Entries.Single();
97             Assert.AreEqual("uart", entry.VariableName);
98             Assert.IsNull(entry.Type);
99             Assert.AreEqual("sysbus", entry.RegistrationInfos.Single().Register.Value);
100             Assert.AreEqual("something", ((StringValue)entry.RegistrationInfos.Single().RegistrationPoint).Value);
101         }
102 
103         [Test]
ShouldParseEntryWithManyRegistrationPoints()104         public void ShouldParseEntryWithManyRegistrationPoints()
105         {
106             var source = @"
107 uart: @{ sysbus 0x100;
108          sysbus 0x200}";
109             var result = Grammar.Description(GetInputFromString(source));
110             Assert.IsTrue(result.WasSuccessful, result.ToString());
111 
112             var entry = result.Value.Entries.Single();
113             Assert.AreEqual("uart", entry.VariableName);
114             Assert.IsNull(entry.Type);
115             var registrationInfos = entry.RegistrationInfos.ToArray();
116             Assert.AreEqual("sysbus", registrationInfos[0].Register.Value);
117             Assert.AreEqual("0x100", ((NumericalValue)registrationInfos[0].RegistrationPoint).Value);
118 
119             Assert.AreEqual("sysbus", registrationInfos[1].Register.Value);
120             Assert.AreEqual("0x200", ((NumericalValue)registrationInfos[1].RegistrationPoint).Value);
121         }
122 
123         [Test]
ShouldParseEntryWithOneAttribute()124         public void ShouldParseEntryWithOneAttribute()
125         {
126             var source = @"
127 uart:
128     baudRate: BaudRate.B9600
129 ";
130             var result = Grammar.Description(GetInputFromString(source));
131             Assert.IsTrue(result.WasSuccessful, result.ToString());
132 
133             var entry = result.Value.Entries.Single();
134             Assert.AreEqual("uart", entry.VariableName);
135             Assert.IsNull(entry.Type);
136 
137             var attribute = (ConstructorOrPropertyAttribute)entry.Attributes.Single();
138             Assert.AreEqual("baudRate", attribute.Name);
139             Assert.AreEqual("B9600", ((EnumValue)attribute.Value).Value);
140         }
141 
142         [Test]
ShouldParseEntryWithTwoAttributes()143         public void ShouldParseEntryWithTwoAttributes()
144         {
145             var source = @"
146 uart:
147     friendlyName: ""some name""
148     size: 0x1000
149 ";
150 
151             var result = Grammar.Description(GetInputFromString(source));
152             Assert.IsTrue(result.WasSuccessful, result.ToString());
153 
154             var entry = result.Value.Entries.Single();
155             var attributes = entry.Attributes;
156             Assert.AreEqual(2, attributes.Count());
157         }
158 
159         [Test]
ShouldParseEntryWithAllAttributes()160         public void ShouldParseEntryWithAllAttributes()
161         {
162             var source = @"
163 uart:
164     model: ""ABC666""
165     numberOfBits: 32
166     sleepTime: 0.01
167     friendUart: otherUart
168     range: <0x1000, +0x100>
169 ";
170             var result = Grammar.Description(GetInputFromString(source));
171             Assert.IsTrue(result.WasSuccessful, result.ToString());
172 
173             var entry = result.Value.Entries.Single();
174             var attributes = entry.Attributes.Cast<ConstructorOrPropertyAttribute>().ToDictionary(x => x.Name, x => x.Value);
175             Assert.AreEqual(5, attributes.Count);
176             Assert.AreEqual("ABC666", ((StringValue)attributes["model"]).Value);
177             Assert.AreEqual("32", ((NumericalValue)attributes["numberOfBits"]).Value);
178             Assert.AreEqual("0.01", ((NumericalValue)attributes["sleepTime"]).Value);
179             Assert.AreEqual("otherUart", ((ReferenceValue)attributes["friendUart"]).Value);
180             Assert.AreEqual(0x1000.By(0x100), ((RangeValue)attributes["range"]).ToRange());
181         }
182 
183         [Test]
ShouldParseEntryWithSimpleIrqEntries()184         public void ShouldParseEntryWithSimpleIrqEntries()
185         {
186             var source = @"
187 uart:
188     1 -> pic@2
189     IRQ -> pic@3
190     -> pic@4";
191 
192             var result = Grammar.Description(GetInputFromString(source));
193             Assert.IsTrue(result.WasSuccessful, result.ToString());
194 
195             var entry = result.Value.Entries.Single();
196             var attributes = entry.Attributes.Cast<IrqAttribute>().ToArray();
197             Assert.AreEqual(1, attributes[0].Sources.Single().Ends.Single().Number);
198             Assert.AreEqual("pic", attributes[0].Destinations.ElementAt(0).DestinationPeripheral.Reference.Value);
199             Assert.AreEqual(2, attributes[0].Destinations.ElementAt(0).Destinations.Single().Ends.Single().Number);
200             Assert.AreEqual("IRQ", attributes[1].Sources.Single().Ends.Single().PropertyName);
201             Assert.IsNull(attributes[2].Sources);
202         }
203 
204         [Test]
ShouldParseEntryWithSimpleMultiplexedIrqEntries()205         public void ShouldParseEntryWithSimpleMultiplexedIrqEntries()
206         {
207             var source = @"
208 uart:
209     1 -> pic@2 | pic1@3
210     -> pic2@4 | pic3@5
211     IRQ -> pic4@6 | pic5@7 | pic6@8 | pic7@9";
212 
213             var result = Grammar.Description(GetInputFromString(source));
214             Assert.IsTrue(result.WasSuccessful, result.ToString());
215 
216             var entry = result.Value.Entries.Single();
217             var attributes = entry.Attributes.Cast<IrqAttribute>().ToArray();
218 
219             Assert.AreEqual(1, attributes[0].Sources.Single().Ends.Single().Number);
220             Assert.AreEqual(2, attributes[0].Destinations.ElementAt(0).Destinations.ElementAt(0).Ends.ElementAt(0).Number);
221             Assert.AreEqual("pic", attributes[0].Destinations.ElementAt(0).DestinationPeripheral.Reference.Value);
222             Assert.AreEqual(3, attributes[0].Destinations.ElementAt(1).Destinations.ElementAt(0).Ends.ElementAt(0).Number);
223             Assert.AreEqual("pic1", attributes[0].Destinations.ElementAt(1).DestinationPeripheral.Reference.Value);
224 
225             Assert.IsNull(attributes[1].Sources);
226             Assert.AreEqual(4, attributes[1].Destinations.ElementAt(0).Destinations.ElementAt(0).Ends.ElementAt(0).Number);
227             Assert.AreEqual("pic2", attributes[1].Destinations.ElementAt(0).DestinationPeripheral.Reference.Value);
228             Assert.AreEqual(5, attributes[1].Destinations.ElementAt(1).Destinations.ElementAt(0).Ends.ElementAt(0).Number);
229             Assert.AreEqual("pic3", attributes[1].Destinations.ElementAt(1).DestinationPeripheral.Reference.Value);
230 
231             Assert.AreEqual("IRQ", attributes[2].Sources.ElementAt(0).Ends.ElementAt(0).PropertyName);
232             Assert.AreEqual(4, attributes[2].Destinations.Count());
233         }
234 
235         [Test]
ShouldParseEntryWithMultiplexedMultiIrqEntries()236         public void ShouldParseEntryWithMultiplexedMultiIrqEntries()
237         {
238             var source = @"
239 uart:
240     [1-2, IRQ] -> pic0@[4-6] | pic1@[7-8, 9] | pic2@[10, 11, 12]";
241 
242             var result = Grammar.Description(GetInputFromString(source));
243             Assert.IsTrue(result.WasSuccessful, result.ToString());
244 
245             var entry = result.Value.Entries.Single();
246             var attribute = entry.Attributes.Cast<IrqAttribute>().Single();
247 
248             var flattenedSources = attribute.Sources.SelectMany(x => x.Ends).ToArray();
249             Assert.AreEqual(1, flattenedSources[0].Number);
250             Assert.AreEqual(2, flattenedSources[1].Number);
251             Assert.AreEqual("IRQ", flattenedSources[2].PropertyName);
252             Assert.AreEqual(3, flattenedSources.Count());
253 
254             Assert.AreEqual("pic0", attribute.Destinations.ElementAt(0).DestinationPeripheral.Reference.Value);
255             Assert.AreEqual(flattenedSources.Count(), attribute.Destinations.ElementAt(0).Destinations.SelectMany(x => x.Ends).Count());
256             Assert.AreEqual(4, attribute.Destinations.ElementAt(0).Destinations.ElementAt(0).Ends.ElementAt(0).Number);
257             Assert.AreEqual(5, attribute.Destinations.ElementAt(0).Destinations.ElementAt(0).Ends.ElementAt(1).Number);
258             Assert.AreEqual(6, attribute.Destinations.ElementAt(0).Destinations.ElementAt(0).Ends.ElementAt(2).Number);
259 
260             Assert.AreEqual("pic1", attribute.Destinations.ElementAt(1).DestinationPeripheral.Reference.Value);
261             Assert.AreEqual(flattenedSources.Count(), attribute.Destinations.ElementAt(1).Destinations.SelectMany(x => x.Ends).Count());
262             Assert.AreEqual(7, attribute.Destinations.ElementAt(1).Destinations.ElementAt(0).Ends.ElementAt(0).Number);
263             Assert.AreEqual(8, attribute.Destinations.ElementAt(1).Destinations.ElementAt(0).Ends.ElementAt(1).Number);
264             Assert.AreEqual(9, attribute.Destinations.ElementAt(1).Destinations.ElementAt(1).Ends.ElementAt(0).Number);
265 
266             Assert.AreEqual("pic2", attribute.Destinations.ElementAt(2).DestinationPeripheral.Reference.Value);
267             Assert.AreEqual(flattenedSources.Count(), attribute.Destinations.ElementAt(2).Destinations.SelectMany(x => x.Ends).Count());
268             Assert.AreEqual(10, attribute.Destinations.ElementAt(2).Destinations.ElementAt(0).Ends.ElementAt(0).Number);
269             Assert.AreEqual(11, attribute.Destinations.ElementAt(2).Destinations.ElementAt(1).Ends.ElementAt(0).Number);
270             Assert.AreEqual(12, attribute.Destinations.ElementAt(2).Destinations.ElementAt(2).Ends.ElementAt(0).Number);
271         }
272 
273         [Test]
ShouldParseEntryWithMultiIrqEntries()274         public void ShouldParseEntryWithMultiIrqEntries()
275         {
276             var source = @"
277 uart:
278     [1-3, IRQ] -> pic @ [2-5]";
279 
280             var result = Grammar.Description(GetInputFromString(source));
281             Assert.IsTrue(result.WasSuccessful, result.ToString());
282 
283             var entry = result.Value.Entries.Single();
284             var attribute = entry.Attributes.Cast<IrqAttribute>().Single();
285             var flattenedSources = attribute.Sources.SelectMany(x => x.Ends).ToArray();
286             var flattenedDestinations = attribute.Destinations.ElementAt(0).Destinations.SelectMany(x => x.Ends).ToArray();
287             Assert.AreEqual(1, flattenedSources[0].Number);
288             Assert.AreEqual(2, flattenedSources[1].Number);
289             Assert.AreEqual(3, flattenedSources[2].Number);
290             Assert.AreEqual("IRQ", flattenedSources[3].PropertyName);
291 
292             Assert.AreEqual(2, flattenedDestinations[0].Number);
293             Assert.AreEqual(3, flattenedDestinations[1].Number);
294             Assert.AreEqual(4, flattenedDestinations[2].Number);
295             Assert.AreEqual(5, flattenedDestinations[3].Number);
296         }
297 
298         [Test]
ShouldParseEntryWithLocalIrqReceiver()299         public void ShouldParseEntryWithLocalIrqReceiver()
300         {
301             var source = @"
302 uart:
303     1 -> something#3@2";
304 
305             var result = Grammar.Description(GetInputFromString(source));
306             Assert.IsTrue(result.WasSuccessful, result.ToString());
307 
308             var entry = result.Value.Entries.Single();
309             var attribute = entry.Attributes.OfType<IrqAttribute>().Single();
310             Assert.AreEqual(1, attribute.Sources.Single().Ends.Single().Number);
311             Assert.AreEqual("something", attribute.Destinations.ElementAt(0).DestinationPeripheral.Reference.Value);
312             Assert.AreEqual(3, attribute.Destinations.ElementAt(0).DestinationPeripheral.LocalIndex);
313             Assert.AreEqual(2, attribute.Destinations.ElementAt(0).Destinations.Single().Ends.Single().Number);
314         }
315 
316         [Test]
ShouldParseInitAttributeWithOneLine()317         public void ShouldParseInitAttributeWithOneLine()
318         {
319             var source = @"
320 uart:
321     init:
322         DoSomething 3
323 ";
324             var result = Grammar.Description(GetInputFromString(source));
325             Assert.IsTrue(result.WasSuccessful, result.ToString());
326 
327             var onlyLine = ((InitAttribute)result.Value.Entries.Single().Attributes.Single()).Lines.Single();
328             Assert.AreEqual("DoSomething 3", onlyLine);
329         }
330 
331         [Test]
ShouldParseInitAttributeWithMoreLines()332         public void ShouldParseInitAttributeWithMoreLines()
333         {
334             var source = @"
335 uart:
336     init:
337         Method1 a b
338         Method2 true
339         Method3";
340 
341             var result = Grammar.Description(GetInputFromString(source));
342             Assert.IsTrue(result.WasSuccessful, result.ToString());
343 
344             var lines = ((InitAttribute)result.Value.Entries.Single().Attributes.Single()).Lines.ToArray();
345             Assert.AreEqual("Method1 a b", lines[0]);
346             Assert.AreEqual("Method2 true", lines[1]);
347             Assert.AreEqual("Method3", lines[2]);
348         }
349 
350         [Test]
ShouldParseInitAttributeWithSemicolonInQuotes()351         public void ShouldParseInitAttributeWithSemicolonInQuotes()
352         {
353             var source = @"
354 uart:
355     init:
356         CallMethod ""string ; with semicolon""
357 ";
358             var result = Grammar.Description(GetInputFromString(source));
359             Assert.IsTrue(result.WasSuccessful, result.ToString());
360 
361             var lines = ((InitAttribute)result.Value.Entries.Single().Attributes.Single()).Lines.ToArray();
362             Assert.AreEqual("CallMethod \"string ; with semicolon\"", lines.Single());
363         }
364 
365         [Test]
ShouldParseObjectValue()366         public void ShouldParseObjectValue()
367         {
368             var source = @"
369 display: Display
370     resolution: new Point
371         x: 640
372         y: 480
373 ";
374 
375             var result = Grammar.Description(GetInputFromString(source));
376             Assert.IsTrue(result.WasSuccessful, result.ToString());
377 
378             var objectValue = ((ObjectValue)((ConstructorOrPropertyAttribute)result.Value.Entries.Single().Attributes.Single()).Value);
379             Assert.AreEqual("Point", (string)objectValue.TypeName);
380             var attributes = objectValue.Attributes.Cast<ConstructorOrPropertyAttribute>().ToDictionary(x => x.Name, x => x.Value);
381             Assert.AreEqual(2, attributes.Count);
382             Assert.AreEqual("640", ((NumericalValue)attributes["x"]).Value);
383             Assert.AreEqual("480", ((NumericalValue)attributes["y"]).Value);
384         }
385 
386         [Test]
ShouldParseTwoEntries()387         public void ShouldParseTwoEntries()
388         {
389             var source = @"
390 uart1: UART @ sysbus <0x1000, +0x100>
391     someProperty: someValue
392 
393 uart2: UART @ sysbus <0x2000, +0x100>
394     otherProperty: ""otherValue""
395 ";
396             var result = Grammar.Description(GetInputFromString(source));
397             Assert.IsTrue(result.WasSuccessful, result.ToString());
398 
399             Assert.AreEqual(2, result.Value.Entries.Count());
400         }
401 
402         [Test]
ShouldParseLocalAndNonLocalEntry()403         public void ShouldParseLocalAndNonLocalEntry()
404         {
405             var source = @"
406 peripheral: SomeHub
407 local other: Other";
408 
409             var result = Grammar.Description(GetInputFromString(source));
410             Assert.IsTrue(result.WasSuccessful, result.ToString());
411 
412             var entries = result.Value.Entries.ToArray();
413             Assert.IsFalse(entries[0].IsLocal);
414             Assert.IsTrue(entries[1].IsLocal);
415         }
416 
417         [Test]
ShouldHandlePrefixedUsing()418         public void ShouldHandlePrefixedUsing()
419         {
420             var source = @"
421 using ""file1""
422 using ""file2"" prefixed ""prefix_""";
423 
424             var result = Grammar.Description(GetInputFromString(source));
425             Assert.IsTrue(result.WasSuccessful, result.ToString());
426 
427             var usings = result.Value.Usings.ToArray();
428             Assert.AreEqual("file1", usings[0].Path.Value);
429             Assert.AreEqual("file2", usings[1].Path.Value);
430             Assert.IsNull(usings[0].Prefix);
431             Assert.AreEqual("prefix_", usings[1].Prefix);
432         }
433 
434         [Test]
ShouldParseExample()435         public void ShouldParseExample()
436         {
437             var source = @"
438 screen: Display@graphicsCard1
439     resolution: new Point { x: 5; y: 6 }
440     refreshMode: Automatic
441     model: ""SuperDisplay""
442     -> ic@3
443     init:
444         DrawCircle 20 20
445         DrawCircle 30 40
446 
447 screen:
448     init:
449         DrawRect 40 50 1
450 
451 screen:
452     init:
453         base init
454         DrawRect 40 50 1
455 
456 other: Display @ sysbus <0x0, +0x100> { refreshMode: Automatic; -> ic@3 }
457 ";
458 
459             var result = Grammar.Description(GetInputFromString(source));
460             Assert.IsTrue(result.WasSuccessful, result.ToString());
461         }
462 
463         [Test]
ShouldParseTwoShortEntries()464         public void ShouldParseTwoShortEntries()
465         {
466             var source = @"
467 uart: UART
468 
469 uart: @sysbus <0x100, +0x100>
470 ";
471 
472             var result = Grammar.Description(GetInputFromString(source));
473             Assert.IsTrue(result.WasSuccessful, result.ToString());
474 
475             Assert.AreEqual(2, result.Value.Entries.Count());
476         }
477 
478         [Test]
ShouldParseUsingAndEntry()479         public void ShouldParseUsingAndEntry()
480         {
481             var source = @"
482 using ""other_file""
483 
484 device: SomeDevice";
485 
486             var result = Grammar.Description(GetInputFromString(source));
487             Assert.IsTrue(result.WasSuccessful, result.ToString());
488 
489             var usingEntry = result.Value.Usings.First();
490             Assert.AreEqual("other_file", usingEntry.Path.Value);
491             var entry = result.Value.Entries.First();
492             Assert.AreEqual("device", entry.VariableName);
493             Assert.AreEqual("SomeDevice", entry.Type.Value);
494         }
495 
496         [Test]
ShouldParseBool()497         public void ShouldParseBool()
498         {
499             var source = @"
500 device: Something @ somewhere
501     BoolProp: true
502     BoolProp2: false
503 ";
504 
505             var result = Grammar.Description(GetInputFromString(source));
506             Assert.IsTrue(result.WasSuccessful, result.ToString());
507 
508             var values = result.Value.Entries.Single().Attributes.OfType<ConstructorOrPropertyAttribute>()
509                                    .Select(x => x.Value).OfType<BoolValue>().ToArray();
510             Assert.AreEqual(2, values.Length);
511             Assert.AreEqual(true, values[0].Value);
512             Assert.AreEqual(false, values[1].Value);
513         }
514 
515         [Test]
ShouldParseWithMixedLineEndings()516         public void ShouldParseWithMixedLineEndings()
517         {
518             var source = new StringBuilder();
519             source.Append("peripheral: SomeHub");
520             source.Append("\n");
521             source.Append("local first_other: Other");
522             source.Append("\r\n");
523             source.Append("local second_other: Other");
524             source.Append("\r\n");
525 
526             var result = Grammar.Description(GetInputFromString(source.ToString()));
527             Assert.IsTrue(result.WasSuccessful, result.ToString());
528         }
529 
530         [Test]
ShouldParseStringWithEscapedBackslashes()531         public void ShouldParseStringWithEscapedBackslashes()
532         {
533             var source = @"
534 uart:
535     string: ""\\escaped backslash: \\, two in a row: \\\\, before quote: \\\"", and one at the end: \\""
536 ";
537             var result = Grammar.Description(GetInputFromString(source));
538             Assert.IsTrue(result.WasSuccessful, result.ToString());
539 
540             var entry = result.Value.Entries.Single();
541             Assert.AreEqual("uart", entry.VariableName);
542             Assert.IsNull(entry.Type);
543 
544             var attribute = (ConstructorOrPropertyAttribute)entry.Attributes.Single();
545             Assert.AreEqual("string", attribute.Name);
546             Assert.AreEqual(@"\escaped backslash: \, two in a row: \\, before quote: \"", and one at the end: \", ((StringValue)attribute.Value).Value);
547         }
548 
549         private static IInput GetInputFromString(string source)
550         {
551             var result = PreLexer.Process(source);
552             if(!result.Any())
553             {
554                 return new Input(string.Empty);
555             }
556             var output = result.Aggregate((x, y) => x + Environment.NewLine + y);
557             return new Input(output);
558         }
559     }
560 }
561