forked from scriptcs/scriptcs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFilePreProcessor.cs
More file actions
155 lines (119 loc) · 5.32 KB
/
FilePreProcessor.cs
File metadata and controls
155 lines (119 loc) · 5.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ScriptCs.Contracts;
namespace ScriptCs
{
public class FilePreProcessor : IFilePreProcessor
{
private readonly ILog _logger;
private readonly IEnumerable<ILineProcessor> _lineProcessors;
private readonly IFileSystem _fileSystem;
[Obsolete("Support for Common.Logging types was deprecated in version 0.15.0 and will soon be removed.")]
public FilePreProcessor(IFileSystem fileSystem, Common.Logging.ILog logger, IEnumerable<ILineProcessor> lineProcessors)
: this(fileSystem, new CommonLoggingLogProvider(logger), lineProcessors)
{
}
public FilePreProcessor(IFileSystem fileSystem, ILogProvider logProvider, IEnumerable<ILineProcessor> lineProcessors)
{
Guard.AgainstNullArgument("fileSystem", fileSystem);
Guard.AgainstNullArgument("logProvider", logProvider);
_fileSystem = fileSystem;
_logger = logProvider.ForCurrentType();
_lineProcessors = lineProcessors;
}
public virtual FilePreProcessorResult ProcessFile(string path)
{
return Process(context => ParseFile(path, context));
}
public virtual FilePreProcessorResult ProcessScript(string script)
{
var scriptLines = _fileSystem.SplitLines(script).ToList();
return Process(context => ParseScript(scriptLines, context));
}
protected virtual FilePreProcessorResult Process(Action<FileParserContext> parseAction)
{
Guard.AgainstNullArgument("parseAction", parseAction);
var context = new FileParserContext();
_logger.DebugFormat("Starting pre-processing");
parseAction(context);
var code = GenerateCode(context);
_logger.DebugFormat("Pre-processing finished successfully");
return new FilePreProcessorResult
{
Namespaces = context.Namespaces,
LoadedScripts = context.LoadedScripts,
References = context.References,
Code = code
};
}
protected virtual string GenerateCode(FileParserContext context)
{
Guard.AgainstNullArgument("context", context);
return string.Join(_fileSystem.NewLine, context.BodyLines);
}
public virtual void ParseFile(string path, FileParserContext context)
{
Guard.AgainstNullArgument("path", path);
Guard.AgainstNullArgument("context", context);
var fullPath = _fileSystem.GetFullPath(path);
var filename = Path.GetFileName(path);
if (context.LoadedScripts.Contains(fullPath))
{
_logger.DebugFormat("Skipping {0} because it's already been loaded.", filename);
return;
}
_logger.DebugFormat("Processing {0}...", filename);
// Add script to loaded collection before parsing to avoid loop.
context.LoadedScripts.Add(fullPath);
var scriptLines = _fileSystem.ReadFileLines(fullPath).ToList();
InsertLineDirective(fullPath, scriptLines);
InDirectory(fullPath, () => ParseScript(scriptLines, context));
}
public virtual void ParseScript(List<string> scriptLines, FileParserContext context)
{
Guard.AgainstNullArgument("scriptLines", scriptLines);
Guard.AgainstNullArgument("context", context);
var codeIndex = scriptLines.FindIndex(IsNonDirectiveLine);
for (var index = 0; index < scriptLines.Count; index++)
{
var line = scriptLines[index];
var isBeforeCode = index < codeIndex || codeIndex < 0;
var wasProcessed = _lineProcessors.Any(x => x.ProcessLine(this, context, line, isBeforeCode));
if (!wasProcessed)
{
context.BodyLines.Add(line);
}
}
}
protected virtual void InsertLineDirective(string path, List<string> fileLines)
{
Guard.AgainstNullArgument("fileLines", fileLines);
var bodyIndex = fileLines.FindIndex(line => IsNonDirectiveLine(line) && !IsUsingLine(line));
if (bodyIndex == -1)
{
return;
}
var directiveLine = string.Format("#line {0} \"{1}\"", bodyIndex + 1, path);
fileLines.Insert(bodyIndex, directiveLine);
}
private void InDirectory(string path, Action action)
{
var oldCurrentDirectory = _fileSystem.CurrentDirectory;
_fileSystem.CurrentDirectory = _fileSystem.GetWorkingDirectory(path);
action();
_fileSystem.CurrentDirectory = oldCurrentDirectory;
}
private bool IsNonDirectiveLine(string line)
{
var directiveLineProcessors =
_lineProcessors.OfType<IDirectiveLineProcessor>();
return line.Trim() != string.Empty && !directiveLineProcessors.Any(lp => lp.Matches(line));
}
private static bool IsUsingLine(string line)
{
return line.TrimStart(' ').StartsWith("using ") && !line.Contains("{") && line.Contains(";");
}
}
}