forked from MonoGame/MonoGame
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Preprocessor.cs
179 lines (149 loc) · 5.48 KB
/
Preprocessor.cs
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
using System.Collections.Generic;
using System.IO;
using System.Text;
using CppNet;
namespace TwoMGFX
{
public static class Preprocessor
{
public static string Preprocess(
string effectCode, string filePath, IDictionary<string, string> defines, List<string> dependencies,
IEffectCompilerOutput output)
{
var fullPath = Path.GetFullPath(filePath);
var pp = new CppNet.Preprocessor();
pp.EmitExtraLineInfo = false;
pp.addFeature(Feature.LINEMARKERS);
pp.setListener(new MGErrorListener(output));
pp.setFileSystem(new MGFileSystem(dependencies));
pp.setQuoteIncludePath(new List<string> { Path.GetDirectoryName(fullPath) });
foreach (var define in defines)
pp.addMacro(define.Key, define.Value);
pp.addInput(new MGStringLexerSource(effectCode, true, fullPath));
var result = new StringBuilder();
var endOfStream = false;
while (!endOfStream)
{
var token = pp.token();
switch (token.getType())
{
case CppNet.Token.EOF:
endOfStream = true;
break;
case CppNet.Token.CPPCOMMENT:
break;
case CppNet.Token.CCOMMENT:
{
var tokenText = token.getText();
if (tokenText != null)
{
// Need to preserve line breaks so that line numbers are correct.
foreach (var c in tokenText)
if (c == '\n')
result.Append(c);
}
break;
}
default:
{
var tokenText = token.getText();
if (tokenText != null)
result.Append(tokenText);
break;
}
}
}
return result.ToString();
}
private class MGFileSystem : VirtualFileSystem
{
private readonly List<string> _dependencies;
public MGFileSystem(List<string> dependencies)
{
_dependencies = dependencies;
}
public VirtualFile getFile(string path)
{
return new MGFile(path, _dependencies);
}
public VirtualFile getFile(string dir, string name)
{
return new MGFile(Path.Combine(dir, name), _dependencies);
}
}
private class MGFile : VirtualFile
{
private readonly List<string> _dependencies;
private readonly string _path;
public MGFile(string path, List<string> dependencies)
{
_dependencies = dependencies;
_path = Path.GetFullPath(path);
}
public bool isFile()
{
return File.Exists(_path) && !File.GetAttributes(_path).HasFlag(FileAttributes.Directory);
}
public string getPath()
{
return _path;
}
public string getName()
{
return Path.GetFileName(_path);
}
public VirtualFile getParentFile()
{
return new MGFile(Path.GetDirectoryName(_path), _dependencies);
}
public VirtualFile getChildFile(string name)
{
return new MGFile(Path.Combine(_path, name), _dependencies);
}
public Source getSource()
{
if (!_dependencies.Contains(_path))
_dependencies.Add(_path);
return new MGStringLexerSource(AppendNewlineIfNonePresent(File.ReadAllText(_path)), true, _path);
}
private static string AppendNewlineIfNonePresent(string text)
{
if (!text.EndsWith("\n"))
return text + "\n";
return text;
}
}
private class MGStringLexerSource : StringLexerSource
{
public string Path { get; private set; }
public MGStringLexerSource(string str, bool ppvalid, string fileName)
: base(str.Replace("\r\n", "\n"), ppvalid, fileName)
{
Path = fileName;
}
}
private class MGErrorListener : PreprocessorListener
{
private readonly IEffectCompilerOutput _output;
public MGErrorListener(IEffectCompilerOutput output)
{
_output = output;
}
public void handleWarning(Source source, int line, int column, string msg)
{
_output.WriteWarning(GetPath(source), line, column, msg);
}
public void handleError(Source source, int line, int column, string msg)
{
_output.WriteError(GetPath(source), line, column, msg);
}
private string GetPath(Source source)
{
return ((MGStringLexerSource) source).Path;
}
public void handleSourceChange(Source source, string ev)
{
}
}
}
}