forked from Misaki/GhostEngine
Updated target frameworks to .NET 10.0 across multiple projects for compatibility with the latest features. Refactored namespaces and introduced new classes for shader descriptors, FMOD integration, and DirectX 12 utilities using TerraFX. Replaced `Win32` bindings with TerraFX equivalents for DirectX 12. Added a C# wrapper for FMOD Studio API, including DSP and error handling. Enhanced entity queries, component storage, and query filters for better performance and type safety. Introduced new test projects and updated the solution structure. Added `meshoptimizer` bindings and integrated `meshoptimizer_native.dll`. Improved code readability, maintainability, and performance.
313 lines
7.7 KiB
C#
313 lines
7.7 KiB
C#
namespace Ghost.Shader.Compiler;
|
|
|
|
internal static class TokenStreamImple
|
|
{
|
|
public static Token Peek(ReadOnlySpan<Token> tokens, ref int index, int length)
|
|
{
|
|
return index + length < tokens.Length ? tokens[index + length] : throw new InvalidOperationException("No more tokens available");
|
|
}
|
|
|
|
public static bool TryPeek(ReadOnlySpan<Token> tokens, ref int index, int length, out Token token)
|
|
{
|
|
if (index + length < tokens.Length)
|
|
{
|
|
token = tokens[index + length];
|
|
return true;
|
|
}
|
|
|
|
token = default;
|
|
return false;
|
|
}
|
|
|
|
public static bool TryConsume(ReadOnlySpan<Token> tokens, ref int index, out Token token)
|
|
{
|
|
if (index < tokens.Length)
|
|
{
|
|
token = tokens[index++];
|
|
return true;
|
|
}
|
|
|
|
token = default;
|
|
return false;
|
|
}
|
|
|
|
public static Token Consume(ReadOnlySpan<Token> tokens, ref int index)
|
|
{
|
|
return index < tokens.Length ? tokens[index++] : throw new InvalidOperationException("No more tokens available");
|
|
}
|
|
|
|
public static bool Match(ReadOnlySpan<Token> tokens, ref int index, TokenType type, string? lexeme)
|
|
{
|
|
var t = Peek(tokens, ref index, 0);
|
|
if (!t.Match(type, lexeme))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//index++;
|
|
return true;
|
|
}
|
|
|
|
public static int MatchMany(ReadOnlySpan<Token> tokens, ref int index, TokenType type, string? lexeme)
|
|
{
|
|
var count = 0;
|
|
while (TryPeek(tokens, ref index, 0, out var t) && t.Match(type, lexeme))
|
|
{
|
|
index++;
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
public static Token Expect(ReadOnlySpan<Token> tokens, ref int index, TokenType type, string? lexeme)
|
|
{
|
|
if (!TryPeek(tokens, ref index, 0, out var t))
|
|
{
|
|
throw new InvalidOperationException("Expected token but reached end of stream");
|
|
}
|
|
|
|
if (!t.Match(type, lexeme))
|
|
{
|
|
throw new InvalidOperationException($"Expected token {type}('{lexeme ?? "*"}') but got {t}");
|
|
}
|
|
|
|
index++;
|
|
return t;
|
|
}
|
|
}
|
|
|
|
internal class TokenStream
|
|
{
|
|
private readonly Token[] _tokens;
|
|
private int _index = 0;
|
|
|
|
public int Length => _tokens.Length;
|
|
public int Remaining => _tokens.Length - _index;
|
|
public bool HasMore => _index < _tokens.Length;
|
|
public int Position
|
|
{
|
|
get => _index;
|
|
set
|
|
{
|
|
if (value < 0 || value > _tokens.Length)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), "Position must be within the bounds of the token stream.");
|
|
}
|
|
_index = value;
|
|
}
|
|
}
|
|
|
|
public TokenStream(Token[] tokens)
|
|
{
|
|
_tokens = tokens;
|
|
}
|
|
|
|
public TokenStream(IEnumerable<Token> tokens)
|
|
{
|
|
_tokens = tokens.ToArray();
|
|
}
|
|
|
|
public Token Peek(int length = 0)
|
|
{
|
|
return TokenStreamImple.Peek(_tokens, ref _index, length);
|
|
}
|
|
|
|
public bool TryPeek(out Token token)
|
|
{
|
|
return TokenStreamImple.TryPeek(_tokens, ref _index, 0, out token);
|
|
}
|
|
|
|
public bool TryPeek(int length, out Token token)
|
|
{
|
|
return TokenStreamImple.TryPeek(_tokens, ref _index, length, out token);
|
|
}
|
|
|
|
public bool TryConsume(out Token token)
|
|
{
|
|
return TokenStreamImple.TryConsume(_tokens, ref _index, out token);
|
|
}
|
|
|
|
public Token Consume()
|
|
{
|
|
return TokenStreamImple.Consume(_tokens, ref _index);
|
|
}
|
|
|
|
public bool Match(TokenType type, string? lexeme = null)
|
|
{
|
|
return TokenStreamImple.Match(_tokens, ref _index, type, lexeme);
|
|
}
|
|
|
|
public int MatchMany(TokenType type, string? lexeme = null)
|
|
{
|
|
return TokenStreamImple.MatchMany(_tokens, ref _index, type, lexeme);
|
|
}
|
|
|
|
public Token Expect(TokenType type, string? lexeme = null)
|
|
{
|
|
return TokenStreamImple.Expect(_tokens, ref _index, type, lexeme);
|
|
}
|
|
|
|
public TokenStreamSlice Slice(int length = -1)
|
|
{
|
|
if (length <= 0)
|
|
{
|
|
length = _tokens.Length - _index;
|
|
}
|
|
|
|
var slice = _tokens.AsSpan().Slice(_index, length);
|
|
_index += length;
|
|
return new TokenStreamSlice(slice);
|
|
}
|
|
|
|
public TokenStreamSlice SliceNextBlock()
|
|
{
|
|
var length = 0;
|
|
var lBraceCount = 0;
|
|
var rBraceCount = 0;
|
|
|
|
Token nextToken;
|
|
|
|
do
|
|
{
|
|
nextToken = Peek(length);
|
|
|
|
if (length > 0 && lBraceCount > 0 && lBraceCount == rBraceCount)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (nextToken.Match(TokenType.LBrace))
|
|
{
|
|
lBraceCount++;
|
|
}
|
|
else if (nextToken.Match(TokenType.RBrace))
|
|
{
|
|
rBraceCount++;
|
|
}
|
|
|
|
length++;
|
|
}
|
|
while (_index + length < _tokens.Length);
|
|
|
|
return Slice(length);
|
|
}
|
|
}
|
|
|
|
internal ref struct TokenStreamSlice
|
|
{
|
|
private readonly ReadOnlySpan<Token> _tokens;
|
|
private int _index;
|
|
|
|
public readonly int Length => _tokens.Length;
|
|
public readonly int Remaining => _tokens.Length - _index;
|
|
public readonly bool HasMore => _index < _tokens.Length;
|
|
|
|
public int Position
|
|
{
|
|
readonly get => _index;
|
|
set
|
|
{
|
|
if (value < 0 || value > _tokens.Length)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), "Position must be within the bounds of the token stream.");
|
|
}
|
|
_index = value;
|
|
}
|
|
}
|
|
|
|
internal TokenStreamSlice(ReadOnlySpan<Token> tokens)
|
|
{
|
|
_tokens = tokens;
|
|
_index = 0;
|
|
}
|
|
|
|
public Token Peek(int length = 0)
|
|
{
|
|
return TokenStreamImple.Peek(_tokens, ref _index, length);
|
|
}
|
|
|
|
public bool TryPeek(out Token token)
|
|
{
|
|
return TokenStreamImple.TryPeek(_tokens, ref _index, 0, out token);
|
|
}
|
|
|
|
public bool TryPeek(int length, out Token token)
|
|
{
|
|
return TokenStreamImple.TryPeek(_tokens, ref _index, length, out token);
|
|
}
|
|
|
|
public bool TryConsume(out Token token)
|
|
{
|
|
return TokenStreamImple.TryConsume(_tokens, ref _index, out token);
|
|
}
|
|
|
|
public Token Consume()
|
|
{
|
|
return TokenStreamImple.Consume(_tokens, ref _index);
|
|
}
|
|
|
|
public bool Match(TokenType type, string? lexeme = null)
|
|
{
|
|
return TokenStreamImple.Match(_tokens, ref _index, type, lexeme);
|
|
}
|
|
|
|
public int MatchMany(TokenType type, string? lexeme = null)
|
|
{
|
|
return TokenStreamImple.MatchMany(_tokens, ref _index, type, lexeme);
|
|
}
|
|
|
|
public Token Expect(TokenType type, string? lexeme = null)
|
|
{
|
|
return TokenStreamImple.Expect(_tokens, ref _index, type, lexeme);
|
|
}
|
|
|
|
public TokenStreamSlice Slice(int length = -1)
|
|
{
|
|
if (length <= 0)
|
|
{
|
|
length = _tokens.Length - _index;
|
|
}
|
|
|
|
var slice = _tokens.Slice(_index, length);
|
|
_index += length;
|
|
return new TokenStreamSlice(slice);
|
|
}
|
|
|
|
public TokenStreamSlice SliceNextBlock()
|
|
{
|
|
var length = 0;
|
|
var lBraceCount = 0;
|
|
var rBraceCount = 0;
|
|
|
|
do
|
|
{
|
|
var nextToken = Peek(length);
|
|
|
|
if (length > 0 && lBraceCount > 0 && lBraceCount == rBraceCount)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (nextToken.Match(TokenType.LBrace))
|
|
{
|
|
lBraceCount++;
|
|
}
|
|
else if (nextToken.Match(TokenType.RBrace))
|
|
{
|
|
rBraceCount++;
|
|
}
|
|
|
|
length++;
|
|
}
|
|
while (_index + length < _tokens.Length);
|
|
|
|
if (lBraceCount != rBraceCount)
|
|
{
|
|
throw new InvalidOperationException("Unmatched braces in token stream.");
|
|
}
|
|
|
|
return Slice(length);
|
|
}
|
|
}
|