Files
LuaCsForBarotraumaEP/Libraries/MonoGame.Framework/Src/Tools/2MGFX/Preprocessor.cs
2019-06-25 16:00:44 +03:00

185 lines
5.8 KiB
C#

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);
effectCode = effectCode.Replace("#line", "//--WORKAROUND#line");
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:
if (token.getText().StartsWith("//--WORKAROUND#line"))
{
result.Append(token.getText().Replace("//--WORKAROUND#line", "#line"));
}
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)
{
}
}
}
}