SND\AstrorEnales_cp 9eca0e4bcd - Fixed a small issue with comment out multiline comments parsing
- Started refactoring some code in the hlsl parser
- Brought the test coverage of the hlsl parser back to 100%
2012-08-17 10:07:35 +00:00

484 lines
10 KiB
C#

using System;
using System.Collections.Generic;
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace HLSLParser
{
/// <summary>
/// http://msdn.microsoft.com/en-us/library/windows/desktop/bb509706%28v=vs.85%29.aspx
/// </summary>
public class Variable : IShaderElement
{
#region Constants
private static char[] SemanticEndChars = new char[]
{
' ', ':', '<', ';', '='
};
private static readonly List<string> AllTypeModifiers = new List<string>(
new string[]
{
"const",
"row_major",
"column_major",
"extern",
"nointerpolation",
"precise",
"shared",
"groupshared",
"static",
"uniform",
"volatile",
// struct additions
"linear",
"centroid",
"noperspective",
"sample"
});
private static readonly List<string> AllTypeNames = new List<string>(
new string[]
{
"int",
"bool",
"uint",
"dword",
"half",
"float",
"double",
// "min16float",
// "min10float",
// "min16int",
// "min12int",
// "min16uint",
// vector <Type, Number>
"vector",
// matrix <Type, Rows, Columns>
"matrix",
"texture",
"Texture2D",
});
#endregion
#region Public
public string[] TypeModifiers
{
get;
private set;
}
public string Name
{
get;
private set;
}
public string InitialValue
{
get;
private set;
}
public int ArraySize
{
get;
private set;
}
public string Type
{
get;
private set;
}
public string Annotations
{
get;
private set;
}
public string Semantic
{
get;
private set;
}
public string Packoffset
{
get;
private set;
}
public string Register
{
get;
private set;
}
public int[] Dimensions
{
get;
private set;
}
#endregion
#region Constructor
protected Variable(ParseTextWalker walker)
{
ParseType(walker);
ReadNameAndArraySize(walker);
ParseExtraParameters(walker);
ParseAnnotations(walker);
ReadInitialValue(walker);
if (walker.Text.StartsWith(";"))
{
walker.Seek(1);
}
}
#endregion
#region ParseType
private void ParseType(ParseTextWalker walker)
{
string currentText = walker.Text;
int nextSpaceIndex = FindInitialTypeEndSpace(currentText);
string variableType = currentText.Substring(0, nextSpaceIndex);
walker.Seek(nextSpaceIndex + 1);
variableType = ResolveMatrixAndArraySyntax(variableType);
ParseDimensions(variableType);
}
#endregion
#region FindInitialTypeEndSpace
private int FindInitialTypeEndSpace(string text)
{
int searchScope = 0;
if (text.StartsWith("vector") ||
text.StartsWith("matrix"))
{
searchScope = text.IndexOf('>');
}
return text.IndexOf(' ', searchScope);
}
#endregion
#region ResolveMatrixAndArraySyntax
private string ResolveMatrixAndArraySyntax(string text)
{
if (text.Contains("<") &&
text.StartsWith("matrix") ||
text.StartsWith("vector"))
{
text = text.Substring(text.IndexOf('<') + 1);
text = text.Trim().TrimEnd('>');
string[] parts = text.Split(',');
text = parts[0].Trim();
for (int index = 1; index < parts.Length; index++)
{
text += (index > 1 ? "x" : "") + parts[index].Trim();
}
}
return text;
}
#endregion
#region ParseDimensions
private void ParseDimensions(string typeText)
{
List<int> dimensions = new List<int>();
Type = typeText;
int numeralRemoverIndex = typeText.Length - 1;
while (numeralRemoverIndex >= 1)
{
if (Char.IsDigit(Type[numeralRemoverIndex]))
{
dimensions.Insert(0, int.Parse(Type[numeralRemoverIndex].ToString()));
Type = Type.Substring(0, numeralRemoverIndex);
}
else if (Type[numeralRemoverIndex] == 'x' &&
Char.IsDigit(Type[numeralRemoverIndex - 1]))
{
Type = Type.Substring(0, numeralRemoverIndex);
}
else
{
break;
}
numeralRemoverIndex--;
}
Dimensions = dimensions.ToArray();
}
#endregion
#region ReadNameAndArraySize
private void ReadNameAndArraySize(ParseTextWalker walker)
{
string currentText = walker.Text;
int nameIndex = 0;
while (nameIndex < currentText.Length)
{
char currentChar = currentText[nameIndex];
if (currentChar == ' ' ||
currentChar == ':' ||
currentChar == '<' ||
currentChar == ';' ||
currentChar == '=')
{
break;
}
Name += currentChar;
nameIndex++;
}
if (Name.Contains("["))
{
Name = Name.TrimEnd(']');
int openBraceIndex = Name.IndexOf('[');
ArraySize = int.Parse(Name.Substring(openBraceIndex + 1));
Name = Name.Substring(0, openBraceIndex);
}
walker.Seek(nameIndex);
}
#endregion
#region ParseExtraParameters
private void ParseExtraParameters(ParseTextWalker walker)
{
string currentText = walker.Text;
char currentChar = currentText[0];
if (currentChar == '<' ||
currentChar == ';' ||
currentChar == '=')
{
return;
}
int afterColonIndex = 1;
string extraText = currentText.Substring(afterColonIndex);
if (extraText.Trim().StartsWith("packoffset"))
{
int endIndex = extraText.IndexOf(')') + 1;
Packoffset = extraText.Substring(0, endIndex).Trim();
walker.Seek(endIndex + afterColonIndex);
}
else if (extraText.Trim().StartsWith("register"))
{
int endIndex = extraText.IndexOf(')') + 1;
Register = extraText.Substring(0, endIndex).Trim();
walker.Seek(endIndex + afterColonIndex);
}
else
{
int beforeLength = extraText.Length;
extraText = extraText.TrimStart(' ');
int lowestEndIndex = -1;
foreach (char semanticEndChar in SemanticEndChars)
{
int indexOfEndChar = extraText.IndexOf(semanticEndChar);
if (indexOfEndChar != -1 &&
(lowestEndIndex == -1 ||
indexOfEndChar < lowestEndIndex))
{
lowestEndIndex = indexOfEndChar;
}
}
Semantic = extraText.Substring(0, lowestEndIndex).Trim();
walker.Seek(lowestEndIndex + afterColonIndex + (beforeLength - extraText.Length));
}
}
#endregion
#region ParseAnnotations
private void ParseAnnotations(ParseTextWalker walker)
{
string currentText = walker.Text;
if (currentText[0] != '<')
return;
int endIndex = currentText.IndexOf('>');
Annotations = currentText.Substring(1, endIndex - 1);
walker.Seek(endIndex + 1);
}
#endregion
#region ReadInitialValue
private void ReadInitialValue(ParseTextWalker walker)
{
string text = walker.Text;
if (text[0] == '<' ||
text[0] == ';' ||
text[0] == ':')
{
return;
}
int valueEndIndex = text.IndexOf(';', 1);
InitialValue = text.Substring(1, valueEndIndex - 1);
InitialValue = InitialValue.Trim();
}
#endregion
#region GetTypeModifiers
public static string[] GetTypeModifiers(ParseTextWalker walker)
{
if (walker == null)
return new string[0];
if (String.IsNullOrEmpty(walker.Text))
return new string[0];
string currentText = walker.Text;
int firstSpaceIndex = currentText.IndexOf(' ');
if (firstSpaceIndex == -1)
{
return AllTypeModifiers.Contains(currentText) ?
new string[] { currentText } :
new string[0];
}
var result = new List<string>();
while (firstSpaceIndex != -1)
{
string currentElement = currentText.Substring(0, firstSpaceIndex);
if (AllTypeModifiers.Contains(currentElement))
{
result.Add(currentElement);
}
else
{
break;
}
walker.Seek(firstSpaceIndex + 1);
currentText = walker.Text;
firstSpaceIndex = currentText.IndexOf(' ');
}
return result.ToArray();
}
#endregion
#region IsVariableFollowing
public static bool IsVariableFollowing(ParseTextWalker walker)
{
string currentText = walker.Text;
foreach (string typeName in AllTypeNames)
{
if (currentText.StartsWith(typeName))
return true;
}
return false;
}
#endregion
#region TryParse
public static Variable TryParse(ParseTextWalker walker)
{
string[] typeModifiersFound = GetTypeModifiers(walker);
if (IsVariableFollowing(walker))
{
return new Variable(walker)
{
TypeModifiers = typeModifiersFound,
};
}
else
return null;
}
#endregion
#region ToString
public override string ToString()
{
string result = "";
result = AddTypeModifiersToString(result);
result += Type;
result = AddDimensionsToString(result);
result += " " + Name;
if (ArraySize > 0)
{
result += "[" + ArraySize + "]";
}
if (String.IsNullOrEmpty(Semantic) == false)
{
result += " : " + Semantic;
}
if (String.IsNullOrEmpty(Packoffset) == false)
{
result += " : " + Packoffset;
}
if (String.IsNullOrEmpty(Register) == false)
{
result += " : " + Register;
}
if (String.IsNullOrEmpty(Annotations) == false)
{
result += " <" + Annotations + ">";
}
if (String.IsNullOrEmpty(InitialValue) == false)
{
result += " = " + InitialValue;
}
result += ";";
return result;
}
#endregion
#region AddTypeModifiersToString
private string AddTypeModifiersToString(string text)
{
foreach (string modifier in TypeModifiers)
{
text += modifier + " ";
}
return text;
}
#endregion
#region AddDimensionsToString
private string AddDimensionsToString(string text)
{
for (int index = 0; index < Dimensions.Length; index++)
{
text += (index > 0 ? "x" : "") + Dimensions[index];
}
return text;
}
#endregion
}
}