You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

2007 lines
73 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
namespace UnityEditor.Rendering.HighDefinition
{
internal enum HlslNativeType
{
_unknown, // default, unset
_invalid, // known to be invalid because something went wrong with parsing
_void,
_float,
_float1,
_float2,
_float3,
_float4,
_int,
_int1,
_int2,
_int3,
_int4,
_half,
_half1,
_half2,
_half3,
_half4,
_uint,
_uint1,
_uint2,
_uint3,
_uint4,
_bool,
_bool1,
_bool2,
_bool3,
_bool4,
_float1x2,
_float2x2,
_float3x2,
_float4x2,
_int1x2,
_int2x2,
_int3x2,
_int4x2,
_half1x2,
_half2x2,
_half3x2,
_half4x2,
_uint1x2,
_uint2x2,
_uint3x2,
_uint4x2,
_bool1x2,
_bool2x2,
_bool3x2,
_bool4x2,
_float1x3,
_float2x3,
_float3x3,
_float4x3,
_int1x3,
_int2x3,
_int3x3,
_int4x3,
_half1x3,
_half2x3,
_half3x3,
_half4x3,
_uint1x3,
_uint2x3,
_uint3x3,
_uint4x3,
_bool1x3,
_bool2x3,
_bool3x3,
_bool4x3,
_float1x4,
_float2x4,
_float3x4,
_float4x4,
_int1x4,
_int2x4,
_int3x4,
_int4x4,
_half1x4,
_half2x4,
_half3x4,
_half4x4,
_uint1x4,
_uint2x4,
_uint3x4,
_uint4x4,
_bool1x4,
_bool2x4,
_bool3x4,
_bool4x4,
_Texture,
_Texture1D,
_Texture1DArray,
_Texture2D,
_Texture2DArray,
_Texture3D,
_TextureCUBE,
_TextureCUBEArray,
_SamplerState,
_SamplerComparisonState,
_RWTexture2D,
_RWTexture2DArray,
_RWTexture3D,
_struct, // user defined, of course
}
internal enum HlslOp
{
Invalid, //
ScopeReslution, // ::
PostIncrement, // ++
PostDecrement, // --
FunctionalCast, // int()
FunctionalCall, // func()
Subscript, // []
MemberAccess, // .
PreIncrement, // ++
PreDecrement, // --
UnaryPlus, // +
UnaryMinus, // -
LogicalNot, // !
BitwiseNot, // ~
CStyleCast, // (int)
Dereference, // * - not legal in HLSL?
AddressOf, // & - not legal in HLSL?
Sizeof, // sizeof
PointerToMemberDot, // .* - not legal in HLSL
PointerToMemorArrow, // ->* - not legal in HLSL
Mul, // *
Div, // /
Mod, // %
Add, // +
Sub, // -
ShiftL, // <<
ShiftR, // >>
ThreeWayCompare, // <=> - never used this
LessThan, // <
GreaterThan, // >
LessEqual, // <=
GreaterEqual, // >=
CompareEqual, // ==
NotEqual, // !=
BitwiseAnd, // &
BitwiseXor, // ^
BitwiseOr, // |
LogicalAnd, // &&
LogicalOr, // ||
TernaryQuestion, // ?
TernaryColon, // :
Assignment, // =
AddEquals, // +=
SubEquals, // -=
MulEquals, // *=
DivEquals, // /=
ModEquals, // %=
ShiftLEquals, // <<=
ShiftREquals, // >>=
AndEquals, // &=
XorEquals, // ^=
OrEquals, // |=
Comma, // ,
}
internal enum HlslStatementType
{
If,
Switch,
Case,
Break,
Continue,
Default,
Goto,
Label,
For,
Do,
While,
Expression,
Return,
}
internal enum ApdAllowedState
{
OnlyApd,
OnlyFpd,
AllowApdVariation,
Any
}
internal class HlslTree
{
internal class Node
{
internal Node()
{
}
internal virtual List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
return new List<string>();
}
internal virtual bool IsNodeValid()
{
return true;
}
internal virtual HlslParser.TypeInfo GetNodeTypeInfo(HlslTree tree)
{
HlslParser.TypeInfo ret = new HlslParser.TypeInfo();
ret.identifier = "";
ret.nativeType = HlslNativeType._unknown;
ret.allowedState = ApdAllowedState.Any;
return ret;
}
internal virtual string GetShortName()
{
return "Node";
}
}
static internal string IndentFromDepth(int depth)
{
char[] data = new char[depth * 4];
System.Array.Fill(data, ' ');
return new string(data);
}
static internal void AppendNodeVecLinesToList(ref List<string> debugLines, int[] nodeIds, HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth)
{
for (int i = 0; i < nodeIds.Length; i++)
{
AppendNodeLinesToList(ref debugLines, nodeIds[i], tree, tokenizer, unityReserved, depth);
}
}
static string DebugIdHelper(int id)
{
return " (" + id.ToString() + ")";
}
static internal void AppendNodeLinesToList(ref List<string> debugLines, int nodeId, HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth)
{
{
int id = nodeId;
if (id >= 0)
{
Node node = tree.allNodes[id];
List<string> childLines = node.DebugLines(tree, tokenizer, unityReserved, depth + 1, id);
debugLines.AddRange(childLines);
}
else
{
debugLines.Add(IndentFromDepth(depth + 1) + "<invalid node>");
}
}
}
internal class NodeTopLevel : Node
{
internal NodeTopLevel()
{
statements = new int[0];
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "TopLevel" + DebugIdHelper(nodeId));
for (int i = 0; i < statements.Length; i++)
{
AppendNodeLinesToList(ref ret, statements[i], tree, tokenizer, unityReserved, depth + 1);
}
return ret;
}
internal override string GetShortName()
{
return "TopLevel";
}
internal int[] statements; // struct declarations and functions. will add globals later.
internal HlslTokenizer.CodeSection[] codeSections;
}
internal class NodeStruct : Node
{
internal NodeStruct()
{
nameTokenId = -1;
structInfoId = -1;
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
string myName = tokenizer.GetTokenData(nameTokenId);
ret.Add(IndentFromDepth(depth) + "struct " + myName + DebugIdHelper(nodeId));
AppendNodeVecLinesToList(ref ret, declarations, tree, tokenizer, unityReserved, depth);
return ret;
}
internal override string GetShortName()
{
return "Struct";
}
internal int nameTokenId;
internal int[] declarations;
internal int structInfoId;
}
// reserved structs used by unity HLSL
internal class NodeUnityStruct : Node
{
internal NodeUnityStruct()
{
unityName = null;
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "unity_struct " + unityName + DebugIdHelper(nodeId));
return ret;
}
internal override string GetShortName()
{
return "UnityStruct";
}
internal string unityName;
}
internal class NodeFunctionPrototype : Node
{
internal int returnTokenId;
internal int nameTokenId;
internal int[] declarations;
internal int protoId = -1;
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
string myReturn = tokenizer.GetTokenData(returnTokenId);
string myName = tokenizer.GetTokenData(nameTokenId);
ret.Add(IndentFromDepth(depth) + "prototype " + myReturn + " " + myName + DebugIdHelper(nodeId));
AppendNodeVecLinesToList(ref ret, declarations, tree, tokenizer, unityReserved, depth + 1);
return ret;
}
internal override string GetShortName()
{
return "FuncProto";
}
}
// a prototype into an external function that we don't actually have tokens for
internal class NodeFunctionPrototypeExternal : Node
{
internal HlslUtil.PrototypeInfo protoInfo;
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "func_proto_external " + protoInfo.identifier + DebugIdHelper(nodeId));
ret.Add(IndentFromDepth(depth + 1) + "returns - " + protoInfo.returnType.DebugString());
for (int i = 0; i < protoInfo.paramInfoVec.Length; i++)
{
ret.Add(IndentFromDepth(depth + 1) + "param - " + protoInfo.paramInfoVec[i].DebugString());
}
return ret;
}
internal override string GetShortName()
{
return "FuncProtoExternal";
}
}
internal class NodeBlock : Node
{
internal int[] statements;
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "block" + DebugIdHelper(nodeId));
AppendNodeVecLinesToList(ref ret, statements, tree, tokenizer, unityReserved, depth);
return ret;
}
internal override string GetShortName()
{
return "Block";
}
}
internal class NodeStatement : Node
{
internal int expression;
internal HlslStatementType type;
internal int childBlockOrStatement;
internal int[] forExpressions;
internal int elseBlockOrStatement;
internal NodeStatement()
{
expression = -1;
childBlockOrStatement = -1;
elseBlockOrStatement = -1;
forExpressions = new int[0];
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "statement: " + type.ToString() + DebugIdHelper(nodeId));
switch (type)
{
case HlslStatementType.If:
AppendNodeLinesToList(ref ret, expression, tree, tokenizer, unityReserved, depth + 1);
AppendNodeLinesToList(ref ret, childBlockOrStatement, tree, tokenizer, unityReserved, depth + 1);
if (elseBlockOrStatement >= 0)
{
AppendNodeLinesToList(ref ret, elseBlockOrStatement, tree, tokenizer, unityReserved, depth + 1);
}
break;
case HlslStatementType.Switch:
AppendNodeLinesToList(ref ret, expression, tree, tokenizer, unityReserved, depth + 1);
break;
case HlslStatementType.Case:
AppendNodeLinesToList(ref ret, expression, tree, tokenizer, unityReserved, depth + 1);
break;
case HlslStatementType.Break:
break;
case HlslStatementType.Continue:
break;
case HlslStatementType.Default:
break;
case HlslStatementType.Goto:
AppendNodeLinesToList(ref ret, expression, tree, tokenizer, unityReserved, depth + 1);
break;
case HlslStatementType.Label:
AppendNodeLinesToList(ref ret, expression, tree, tokenizer, unityReserved, depth + 1);
break;
case HlslStatementType.For:
HlslUtil.ParserAssert(forExpressions.Length == 3);
AppendNodeLinesToList(ref ret, forExpressions[0], tree, tokenizer, unityReserved, depth + 1);
AppendNodeLinesToList(ref ret, forExpressions[1], tree, tokenizer, unityReserved, depth + 1);
AppendNodeLinesToList(ref ret, forExpressions[2], tree, tokenizer, unityReserved, depth + 1);
AppendNodeLinesToList(ref ret, childBlockOrStatement, tree, tokenizer, unityReserved, depth + 1);
break;
case HlslStatementType.Do:
AppendNodeLinesToList(ref ret, expression, tree, tokenizer, unityReserved, depth + 1);
AppendNodeLinesToList(ref ret, childBlockOrStatement, tree, tokenizer, unityReserved, depth + 1);
break;
case HlslStatementType.While:
AppendNodeLinesToList(ref ret, expression, tree, tokenizer, unityReserved, depth + 1);
AppendNodeLinesToList(ref ret, childBlockOrStatement, tree, tokenizer, unityReserved, depth + 1);
break;
case HlslStatementType.Expression:
AppendNodeLinesToList(ref ret, expression, tree, tokenizer, unityReserved, depth + 1);
break;
case HlslStatementType.Return:
AppendNodeLinesToList(ref ret, expression, tree, tokenizer, unityReserved, depth + 1);
break;
default:
// no op? error?
break;
}
return ret;
}
internal override string GetShortName()
{
return "Statement - " + type.ToString();
}
}
internal class NodeFunction : Node
{
internal NodeFunction()
{
prototypeId = -1;
blockId = -1;
parseErr = "";
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "function" + DebugIdHelper(nodeId));
if (parseErr.Length > 0)
{
ret.Add(IndentFromDepth(depth + 1) + "error: " + parseErr);
}
AppendNodeLinesToList(ref ret, prototypeId, tree, tokenizer, unityReserved, depth + 1);
AppendNodeLinesToList(ref ret, blockId, tree, tokenizer, unityReserved, depth + 1);
return ret;
}
internal override string GetShortName()
{
return "Function";
}
internal int prototypeId; // NodeFunctionPrototype
internal int blockId;
internal string parseErr;
}
internal class NodeDeclaration : Node
{
internal NodeDeclaration()
{
typeNodeId = -1;
nameTokenId = -1;
subTypeNodeId = -1;
modifierTokenId = -1;
initializerId = -1;
structId = -1;
isMacroDecl = false;
macroDeclString = "";
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
string myModifier = (modifierTokenId >= 0) ? tokenizer.GetTokenData(modifierTokenId) + " " : "";
string myName = tokenizer.GetTokenData(nameTokenId);
ret.Add(IndentFromDepth(depth) + "decl " + myName + DebugIdHelper(nodeId));
AppendNodeLinesToList(ref ret, typeNodeId, tree, tokenizer, unityReserved, depth + 1);
if (subTypeNodeId >= 0)
{
AppendNodeLinesToList(ref ret, subTypeNodeId, tree, tokenizer, unityReserved, depth + 1);
}
if (initializerId >= 0)
{
AppendNodeLinesToList(ref ret, initializerId, tree, tokenizer, unityReserved, depth + 1);
}
AppendNodeVecLinesToList(ref ret, arrayDims, tree, tokenizer, unityReserved, depth + 1);
return ret;
}
internal HlslNativeType nativeType;
internal int structId; // if it's a struct, the node containing it
internal int modifierTokenId; // token for the type
//internal int typeTokenId; // token for the type
//internal int subTypeTokenId; // subtype, i.e. for Texture2D<float3> type is Texture2D and subType is float3;
internal int typeNodeId; // token for the type
internal int subTypeNodeId; // subtype, i.e. for Texture2D<float3> type is Texture2D and subType is float3;
internal int nameTokenId; // token for the param name
internal int initializerId;
internal bool isMacroDecl;
internal string macroDeclString;
internal string variableName;
internal string debugType;
internal int[] arrayDims;
internal override string GetShortName()
{
return "Decl: " + variableName;
}
}
internal class NodeBlockInitializer : Node
{
internal NodeBlockInitializer()
{
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
AppendNodeVecLinesToList(ref ret, initNodeIds, tree, tokenizer, unityReserved, depth);
return ret;
}
internal override string GetShortName()
{
return "BlockInitializer";
}
internal int[] initNodeIds;
}
internal class NodeVariable : Node
{
internal NodeVariable()
{
nameTokenId = -1;
nameVariableId = -1;
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
string myName = tokenizer.GetTokenData(nameTokenId);
ret.Add(IndentFromDepth(depth) + "variable " + myName + DebugIdHelper(nodeId));
return ret;
}
internal override HlslParser.TypeInfo GetNodeTypeInfo(HlslTree tree)
{
HlslUtil.ParserAssert(nameVariableId >= 0);
VariableInfo info = tree.allVariables[nameVariableId];
HlslParser.TypeInfo ret = new HlslParser.TypeInfo();
ret = info.typeInfo;
return ret;
}
internal override string GetShortName()
{
return "Variable: " + debugName;
}
internal int nameTokenId; // token for the param name
internal int nameVariableId;
internal string debugName;
}
internal class NodeNativeConstructor : Node
{
internal NodeNativeConstructor()
{
typeTokenId = -1;
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "native_constructor " + nativeType.ToString() + DebugIdHelper(nodeId));
AppendNodeVecLinesToList(ref ret, paramNodeIds, tree, tokenizer, unityReserved, depth);
return ret;
}
internal override HlslParser.TypeInfo GetNodeTypeInfo(HlslTree tree)
{
HlslParser.TypeInfo ret = new HlslParser.TypeInfo();
ret.nativeType = nativeType;
ret.allowedState = ApdAllowedState.Any;
return ret;
}
internal int typeTokenId; // token for the param name
internal HlslNativeType nativeType;
internal int[] paramNodeIds;
internal override string GetShortName()
{
return "NativeConstructor";
}
}
internal class NodeToken : Node
{
internal NodeToken()
{
srcTokenId = -1;
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
string myName = tokenizer.GetTokenData(srcTokenId);
ret.Add(IndentFromDepth(depth) + "token " + myName + DebugIdHelper(nodeId));
return ret;
}
internal override string GetShortName()
{
return "Token";
}
internal int srcTokenId; // token for the param name
}
internal class NodeNativeType : Node
{
internal NodeNativeType()
{
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "nativeType " + nativeType.ToString() + DebugIdHelper(nodeId));
return ret;
}
internal override string GetShortName()
{
return "NativeType: " + nativeType.ToString();
}
internal HlslNativeType nativeType; // token for the param name
}
internal class NodeLiteralOrBool : Node
{
internal NodeLiteralOrBool()
{
nameTokenId = -1;
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
string myName = tokenizer.GetTokenData(nameTokenId);
ret.Add(IndentFromDepth(depth) + "literal_or_bool " + myName + DebugIdHelper(nodeId));
return ret;
}
internal int nameTokenId; // token for the param name
internal string debugName;
internal override string GetShortName()
{
return "Literal: " + debugName;
}
}
internal class NodePassthrough : Node
{
internal NodePassthrough()
{
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
string fullLine = "";
for (int i = 0; i < tokenIds.Length; i++)
{
int tokenId = tokenIds[i];
fullLine += tokenizer.GetTokenData(tokenId);
}
ret.Add(fullLine);
return ret;
}
internal override string GetShortName()
{
return "Passthough";
}
internal int[] tokenIds; // token for the param name
internal bool writeDirect; // if true, we should write this node directly. if fals, this node append it's text in some way to a parent naode
}
internal class NodeExpression : Node
{
internal NodeExpression()
{
lhsNodeId = -1;
rhsNodeId = -1;
opTokenId = -1;
cstyleCastStructId = -1;
paramIds = new int[0];
rhsRhsNodeId = -1; // for ternary
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "expression " + op.ToString() + " " + tokenizer.GetTokenData(opTokenId) + DebugIdHelper(nodeId));
AppendNodeLinesToList(ref ret, lhsNodeId, tree, tokenizer, unityReserved, depth + 1);
bool isBinary = HlslParser.GetOperatorIsBinary(op);
if (isBinary || op == HlslOp.MemberAccess || op == HlslOp.TernaryQuestion || op == HlslOp.Subscript)
{
AppendNodeLinesToList(ref ret, rhsNodeId, tree, tokenizer, unityReserved, depth + 1);
}
if (op == HlslOp.TernaryQuestion)
{
AppendNodeLinesToList(ref ret, rhsRhsNodeId, tree, tokenizer, unityReserved, depth + 1);
}
AppendNodeVecLinesToList(ref ret, paramIds, tree, tokenizer, unityReserved, depth + 1);
return ret;
}
internal override string GetShortName()
{
return "Expression: " + op.ToString();
}
internal int lhsNodeId;
internal int rhsNodeId;
internal int[] paramIds;
internal HlslOp op;
internal int opTokenId;
internal int cstyleCastStructId;
internal int rhsRhsNodeId; // for ternary
internal string debugName;
}
internal class NodeMemberVariable : Node
{
internal NodeMemberVariable()
{
structNodeId = -1;
fieldIndex = -1;
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
HlslUtil.StructInfo structInfo = tree.GetStructInfoFromNodeId(structNodeId, unityReserved);
HlslUtil.FieldInfo fieldInfo = structInfo.fields[fieldIndex];
ret.Add(IndentFromDepth(depth) + "member_variable: " + structInfo.identifier + "." + fieldInfo.identifier + DebugIdHelper(nodeId));
return ret;
}
internal override string GetShortName()
{
return "MemberVariable";
}
internal int structNodeId;
internal int fieldIndex;
}
internal class NodeParenthesisGroup : Node
{
internal NodeParenthesisGroup()
{
childNodeId = -1;
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "( ... ): " + DebugIdHelper(nodeId));
AppendNodeLinesToList(ref ret, childNodeId, tree, tokenizer, unityReserved, depth + 1);
return ret;
}
internal override string GetShortName()
{
return "()";
}
internal int childNodeId;
}
internal class NodeMemberFunction : Node
{
internal NodeMemberFunction()
{
structNodeId = -1;
funcIndex = -1;
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
HlslUtil.StructInfo structInfo = tree.GetStructInfoFromNodeId(structNodeId, unityReserved);
HlslUtil.PrototypeInfo protoInfo = structInfo.prototypes[funcIndex];
ret.Add(IndentFromDepth(depth) + "member_function: " + structInfo.identifier + "." + protoInfo.identifier + DebugIdHelper(nodeId));
AppendNodeVecLinesToList(ref ret, funcParamNodeIds, tree, tokenizer, unityReserved, depth);
return ret;
}
internal override string GetShortName()
{
return "MemberFunc";
}
internal int structNodeId;
internal int funcIndex = -1;
internal int[] funcParamNodeIds;
}
internal class NodeSwizzle : Node
{
internal NodeSwizzle()
{
swizzle = "";
}
internal override List<string> DebugLines(HlslTree tree, HlslTokenizer tokenizer, HlslUnityReserved unityReserved, int depth, int nodeId)
{
List<string> ret = new List<string>();
ret.Add(IndentFromDepth(depth) + "swizzle: ." + swizzle + DebugIdHelper(nodeId));
return ret;
}
internal override string GetShortName()
{
return "Swizzle: " + swizzle;
}
internal string swizzle;
}
internal string[] CalcDebugLines(HlslTokenizer tokenizer, HlslUnityReserved unityReserved)
{
List<string> allLines = new List<string>();
if (topLevelNode >= 0)
{
Node node = allNodes[topLevelNode];
allLines = node.DebugLines(this, tokenizer, unityReserved, 0, topLevelNode);
}
List<string> errLines = GetErrorText(tokenizer);
allLines.AddRange(errLines);
return allLines.ToArray();
}
internal static HlslParser.TypeInfo TypeInfoFromToken(int tokenId, HlslParser parser, ApdAllowedState allowedState)
{
HlslToken rawToken = parser.tokenizer.GetTokenType(tokenId);
string tokenName = parser.tokenizer.GetTokenData(tokenId);
HlslParser.TypeInfo ret = new HlslParser.TypeInfo();
if (HlslTokenizer.IsTokenNativeType(rawToken))
{
HlslNativeType nativeType = parser.tokenToNativeTable[rawToken];
ret = HlslParser.TypeInfo.MakeNativeType(nativeType, 0, allowedState);
}
else if (rawToken == HlslToken._identifier)
{
ret = HlslParser.TypeInfo.MakeStruct(tokenName, 0);
}
else
{
HlslUtil.ParserAssert(false);
}
return ret;
}
// for the struct id, check if it contains name either as a field or a prototype. Assumes no operator overloading for prototypes.
internal void DoesStructHaveDeclaration(out int fieldIndex, out int protoIndex, int structNodeId, string name, HlslUnityReserved unityReserved)
{
HlslTree.Node baseNode = allNodes[structNodeId];
fieldIndex = -1;
protoIndex = -1;
HlslUtil.StructInfo structInfo = GetStructInfoFromNodeId(structNodeId, unityReserved);
// Brute force linear search seams fine. Maybe do a hash lookup later.
for (int i = 0; i < structInfo.fields.Length; i++)
{
if (string.Compare(structInfo.fields[i].identifier, name) == 0)
{
// there should be no duplicate names
HlslUtil.ParserAssert(fieldIndex < 0);
fieldIndex = i;
}
}
for (int i = 0; i < structInfo.prototypes.Length; i++)
{
if (string.Compare(structInfo.prototypes[i].identifier, name) == 0)
{
// there should be no duplicate names
HlslUtil.ParserAssert(protoIndex < 0);
protoIndex = i;
}
}
}
internal int AddNode(Node data, HlslParser parser, bool stillValid)
{
if (!stillValid)
{
return -1;
}
HlslUtil.ParserAssert(allNodes.Count == fullTypeInfo.Count);
int dstNodeId = allNodes.Count;
if (data is NodeFunctionPrototype nodeProto)
{
HlslUtil.PrototypeInfo protoInfo = new HlslUtil.PrototypeInfo();
string functionName = parser.tokenizer.GetTokenData(nodeProto.nameTokenId);
protoInfo.uniqueId = dstNodeId;
protoInfo.identifier = functionName;
// by default, a function prototype return type can be any
protoInfo.returnType = TypeInfoFromToken(nodeProto.returnTokenId, parser, ApdAllowedState.Any);
protoInfo.paramInfoVec = new HlslParser.TypeInfo[nodeProto.declarations.Length];
for (int i = 0; i < nodeProto.declarations.Length; i++)
{
int nodeId = nodeProto.declarations[i];
Node currNode = allNodes[nodeId];
HlslParser.TypeInfo currType = new HlslParser.TypeInfo();
if (currNode is HlslTree.NodeDeclaration decl)
{
int declTypeNode = decl.typeNodeId;
Node declNode = allNodes[declTypeNode];
currType = declNode.GetNodeTypeInfo(this);
}
protoInfo.paramInfoVec[i] = currType;
}
int dstProtoId = parsedFuncStructData.AddPrototype(protoInfo);
nodeProto.protoId = dstProtoId;
}
else if (data is NodeExpression nodeExp)
{
if (nodeExp.op == HlslOp.FunctionalCall)
{
if (nodeExp.lhsNodeId < 0)
{
HlslUtil.ParserAssert(nodeExp.lhsNodeId >= 0);
}
}
if (nodeExp.op == HlslOp.MemberAccess)
{
HlslUtil.ParserAssert(nodeExp.lhsNodeId >= 0);
HlslUtil.ParserAssert(nodeExp.rhsNodeId >= 0);
}
}
else if (data is NodeDeclaration nodeDecl)
{
if (nodeDecl.nativeType == HlslNativeType._struct &&
nodeDecl.structId < 0)
{
HlslUtil.ParserAssert(false);
}
}
allNodes.Add(data);
FullTypeInfo fti = ResolveFullTypeForNode(dstNodeId);
// if we have a failure, check it one more time so that we can easily set a breakpoint and trace into it.
if (fti.nativeType == HlslNativeType._struct && fti.structId < 0 && !fti.isUnityBuiltin)
{
HlslUtil.ParserAssert(false);
}
fullTypeInfo.Add(fti);
return dstNodeId;
}
internal bool IsStructUnityBuiltin(int nodeId)
{
bool isUnityBuiltin = false;
HlslTree.Node node = allNodes[nodeId];
if (node is HlslTree.NodeStruct nodeStruct)
{
isUnityBuiltin = false;
}
else if (node is HlslTree.NodeUnityStruct nodeUnityStruct)
{
isUnityBuiltin = true;
}
else
{
HlslUtil.ParserAssert(false);
}
return isUnityBuiltin;
}
internal HlslUtil.StructInfo GetStructInfoFromNodeId(int nodeId, HlslUnityReserved unityReserved)
{
HlslUtil.StructInfo structInfo = new HlslUtil.StructInfo();
HlslTree.Node node = allNodes[nodeId];
if (node is HlslTree.NodeStruct nodeStruct)
{
structInfo = parsedFuncStructData.allStructs[nodeStruct.structInfoId];
}
else if (node is HlslTree.NodeUnityStruct nodeUnityStruct)
{
int structId = unityReserved.parsedFuncStructData.structFromIdentifer[nodeUnityStruct.unityName];
structInfo = unityReserved.parsedFuncStructData.allStructs[structId];
}
else
{
HlslUtil.ParserAssert(false);
}
return structInfo;
}
internal bool IsIdentifierFunction(string name)
{
return parsedFuncStructData.overloadFromIdentifer.ContainsKey(name);
}
internal int[] GetNodePrototypeIdsForFunction(string name)
{
int overloadGroupId = parsedFuncStructData.overloadFromIdentifer[name];
HlslUtil.ParserAssert(overloadGroupId >= 0);
HlslUtil.OverloadInfo overloadInfo = parsedFuncStructData.allOverloads[overloadGroupId];
HlslUtil.ParserAssert(string.Compare(overloadInfo.identifier, name) == 0);
return overloadInfo.prototypeList.ToArray();
}
internal void PushScope()
{
structLookupStack.Add(new Dictionary<string, int>());
variableLookupStack.Add(new Dictionary<string, int>());
}
internal void PopScope()
{
// we should never be removing the top level stack
HlslUtil.ParserAssert(structLookupStack.Count >= 2);
HlslUtil.ParserAssert(variableLookupStack.Count >= 2);
structLookupStack.RemoveAt(structLookupStack.Count - 1);
variableLookupStack.RemoveAt(variableLookupStack.Count - 1);
}
internal int AddStructInfo(HlslUtil.StructInfo structInfo)
{
int dstIndex = parsedFuncStructData.allStructs.Count;
parsedFuncStructData.allStructs.Add(structInfo);
// If we are at global scope, add this to the name list so that we can look
// it up later. If not at global scope, skip this step and it we can only
// access this StructInfo by the id returned from this function.
int topIndex = structLookupStack.Count - 1;
if (topIndex == 0)
{
parsedFuncStructData.structFromIdentifer.Add(structInfo.identifier, dstIndex);
}
return dstIndex;
}
internal void AddStructIdentifier(string name, int nodeStructId)
{
int topIndex = structLookupStack.Count - 1;
structLookupStack[topIndex].Add(name, nodeStructId);
}
internal void AddVariableIdentifier(VariableInfo variableInfo)
{
int dstIndex = allVariables.Count;
allVariables.Add(variableInfo);
int topIndex = variableLookupStack.Count - 1;
if (variableLookupStack[topIndex].ContainsKey(variableInfo.variableName))
{
HlslUtil.ParserAssert(false);
}
variableLookupStack[topIndex].Add(variableInfo.variableName, dstIndex);
}
internal bool FindVariableInfo(out VariableInfo variableInfo, out int variableId, string identifier)
{
bool found = false;
variableId = -1;
variableInfo = new VariableInfo();
int topIndex = variableLookupStack.Count - 1;
while (topIndex >= 0 && !found)
{
found = variableLookupStack[topIndex].ContainsKey(identifier);
if (found)
{
int id = variableLookupStack[topIndex][identifier];
variableInfo = allVariables[id];
variableId = id;
}
else
{
topIndex--;
}
}
// if we failed to find it in the stack, try the unity globals
if (!found)
{
HlslParser.TypeInfo foundInfo;
found = unityReserved.FindUnityGlobal(out foundInfo, identifier);
if (found)
{
variableInfo.variableName = identifier;
variableInfo.structId = -1;
variableInfo.typeInfo = foundInfo;
variableInfo.declId = -1;
variableId = -1;
}
}
return found;
}
internal struct FullTypeInfo
{
static internal FullTypeInfo MakeInvalid()
{
FullTypeInfo ret = new FullTypeInfo();
ret.valid = false;
ret.hasType = false;
ret.identifier = "";
ret.nativeType = HlslNativeType._invalid;
ret.arrayDims = 0;
ret.structId = -1;
ret.isUnityBuiltin = false;
return ret;
}
static internal FullTypeInfo MakeValidNoType()
{
FullTypeInfo ret = new FullTypeInfo();
ret.valid = true;
ret.hasType = false;
ret.identifier = "";
ret.nativeType = HlslNativeType._invalid;
ret.arrayDims = 0;
ret.structId = -1;
ret.isUnityBuiltin = false;
return ret;
}
static internal FullTypeInfo MakeStruct(string name, int structId, bool isUnityBuiltin)
{
FullTypeInfo ret = new FullTypeInfo();
ret.valid = true;
ret.hasType = true;
ret.identifier = name;
ret.nativeType = HlslNativeType._struct;
ret.arrayDims = 0;
ret.structId = structId;
ret.isUnityBuiltin = isUnityBuiltin;
return ret;
}
static internal FullTypeInfo MakeNativeType(HlslNativeType nativeType)
{
FullTypeInfo ret = new FullTypeInfo();
ret.valid = true;
ret.hasType = true;
ret.identifier = "";
ret.nativeType = nativeType;
ret.arrayDims = 0;
ret.structId = -1;
ret.isUnityBuiltin = false;
return ret;
}
internal string GetTypeString()
{
string ret = "";
if (structId >= 0)
{
ret = identifier;
}
else
{
ret = HlslUtil.GetNativeTypeString(nativeType);
}
return ret;
}
// valid refers to if this node is processed. hasType refers to if the node has some kind of
// type associated. For example, a node describing:
// (3.0 + x) // x is a float
// would return a float1 as the type. However, a statement such as
// x = y + 32;
// would not have a "type" because it's a complete statement.
internal bool valid;
internal bool hasType;
internal string identifier; // used if struct
internal HlslNativeType nativeType; //
internal int arrayDims;
internal int structId;
internal bool isUnityBuiltin;
}
internal struct ErrInfo
{
internal string errText;
internal int errToken;
}
internal struct VariableInfo
{
internal string variableName;
internal HlslParser.TypeInfo typeInfo;
internal int structId;
internal int declId;
internal bool IsValid()
{
return typeInfo.nativeType != HlslNativeType._unknown;
}
}
internal void ApplyError(string text, int tokenId)
{
ErrInfo err = new ErrInfo();
err.errText = text;
err.errToken = tokenId;
errList.Add(err);
}
internal void ResetErrors()
{
errList = new List<ErrInfo>();
}
internal List<string> GetErrorText(HlslTokenizer tokenizer)
{
List<string> dstText = new List<string>();
for (int errIter = 0; errIter < errList.Count; errIter++)
{
ErrInfo info = errList[errIter];
string errLine = "";
int lineIndex = -1;
int charIndex = -1;
string actualText = "";
// we might have errors after EOF (because we skip to EOF on failures), so need to check if token is valid.
if (info.errToken >= 0 && info.errToken < tokenizer.foundTokens.Count)
{
HlslTokenizer.SingleToken singleToken = tokenizer.foundTokens[info.errToken];
lineIndex = singleToken.marker.indexLine;
charIndex = singleToken.marker.indexChar;
actualText = singleToken.data;
}
// TODO: given the line number, we should be parsing #line preprocessor directives to give an accurate source line number,
// but this is fine for now.
if (lineIndex >= 0 && charIndex >= 0)
{
errLine = string.Format("Error at line {0}:{1} - {2}: ", lineIndex + 1, charIndex, actualText);
}
else
{
errLine = string.Format("Error at line <EOF>: ", lineIndex, charIndex);
}
errLine += info.errText;
dstText.Add(errLine);
}
return dstText;
}
internal HlslTree(HlslUnityReserved srcUnityReserved, HlslTokenizer srcTokenizer)
{
tokenizer = srcTokenizer;
unityReserved = srcUnityReserved;
tokenToNativeTable = HlslParser.GenerateTokenToNativeTable();
allNodes = new List<Node>();
prototypesReserved = new List<Node>();
fullTypeInfo = new List<FullTypeInfo>();
parsedFuncStructData = new HlslUtil.ParsedFuncStructData();
topLevelNode = -1;
structLookupStack = new List<Dictionary<string, int>>();
structLookupStack.Add(new Dictionary<string, int>());
allVariables = new List<VariableInfo>();
variableLookupStack = new List<Dictionary<string, int>>();
variableLookupStack.Add(new Dictionary<string, int>());
errList = new List<ErrInfo>();
}
// funcs for type info
internal HlslTree.FullTypeInfo GetFullTypeInfoFromParserInfo(HlslParser.TypeInfo parserTypeInfo)
{
HlslTree.FullTypeInfo ret = new HlslTree.FullTypeInfo();
if (parserTypeInfo.nativeType == HlslNativeType._struct)
{
bool isUnityBuiltin = unityReserved.parsedFuncStructData.structFromIdentifer.ContainsKey(parserTypeInfo.identifier);
if (isUnityBuiltin)
{
int structInfoId = unityReserved.parsedFuncStructData.structFromIdentifer[parserTypeInfo.identifier];
HlslUtil.StructInfo structInfo = unityReserved.parsedFuncStructData.allStructs[structInfoId];
ret = HlslTree.FullTypeInfo.MakeStruct(structInfo.identifier, -1, true);
}
else
{
if (!parsedFuncStructData.structFromIdentifer.ContainsKey(parserTypeInfo.identifier))
{
HlslUtil.ParserAssert(false);
}
int structInfoId = parsedFuncStructData.structFromIdentifer[parserTypeInfo.identifier];
HlslUtil.StructInfo structInfo = parsedFuncStructData.allStructs[structInfoId];
ret = HlslTree.FullTypeInfo.MakeStruct(structInfo.identifier, structInfoId, false);
}
}
else
{
ret = HlslTree.FullTypeInfo.MakeNativeType(parserTypeInfo.nativeType);
}
ret.arrayDims = parserTypeInfo.arrayDims;
return ret;
}
HlslTree.FullTypeInfo GetFullTypeInfoFromRawTokenId(int tokenId)
{
HlslParser.TypeInfo typeInfo = new HlslParser.TypeInfo();
HlslToken tokenType = tokenizer.GetTokenType(tokenId);
string tokenData = tokenizer.GetTokenData(tokenId);
if (tokenToNativeTable.ContainsKey(tokenType))
{
typeInfo.nativeType = tokenToNativeTable[tokenType];
if (typeInfo.nativeType == HlslNativeType._struct)
{
typeInfo.identifier = tokenData;
}
}
else
{
// is there a better choice?
typeInfo.nativeType = HlslNativeType._void;
}
HlslTree.FullTypeInfo dstTypeInfo = GetFullTypeInfoFromParserInfo(typeInfo);
return dstTypeInfo;
}
HlslTree.FullTypeInfo ResolveExpressionType(HlslTree.NodeExpression nodeExpression)
{
HlslTree.FullTypeInfo ret = new HlslTree.FullTypeInfo();
switch (nodeExpression.op)
{
// these opssimply accept the lhs
case HlslOp.PostIncrement: // ++
case HlslOp.PostDecrement: // --
case HlslOp.PreIncrement: // ++
case HlslOp.PreDecrement: // --
case HlslOp.UnaryPlus: // +
case HlslOp.UnaryMinus: // -
case HlslOp.LogicalNot: // !
case HlslOp.BitwiseNot: // ~
// for shift, just accept the lhs because the rhs is the shift amount
case HlslOp.ShiftL: // <<
case HlslOp.ShiftR: // >>
// for assignment and the variations, the return type is the lhs side
case HlslOp.Assignment: // =
case HlslOp.AddEquals: // +=
case HlslOp.SubEquals: // -=
case HlslOp.MulEquals: // *=
case HlslOp.DivEquals: // /=
case HlslOp.ModEquals: // %=
case HlslOp.ShiftLEquals: // <<=
case HlslOp.ShiftREquals: // >>=
case HlslOp.AndEquals: // &=
case HlslOp.XorEquals: // ^=
case HlslOp.OrEquals: // |=
ret = fullTypeInfo[nodeExpression.lhsNodeId];
break;
// these ops are not supported
case HlslOp.Invalid: //
case HlslOp.ScopeReslution: // ::
case HlslOp.Dereference: // * - not legal in HLSL?
case HlslOp.AddressOf: // & - not legal in HLSL?
case HlslOp.PointerToMemberDot: // .* - not legal in HLSL
case HlslOp.PointerToMemorArrow: // ->* - not legal in HLSL
case HlslOp.ThreeWayCompare: // <=> - never used this
ret = HlslTree.FullTypeInfo.MakeInvalid();
break;
case HlslOp.Subscript: // []
{
ret = fullTypeInfo[nodeExpression.lhsNodeId];
if (ret.arrayDims > 0)
{
ret.arrayDims--;
}
else
{
// if dims are zero, then we might be a swizzle
HlslNativeType baseType = HlslUtil.GetNativeBaseType(ret.nativeType);
int numRows = HlslUtil.GetNumRows(ret.nativeType);
int numCols = HlslUtil.GetNumCols(ret.nativeType);
if (numRows >= 2 && numCols >= 2)
{
// For example, convert a float3x4 into a float4;
ret.nativeType = HlslUtil.GetBaseTypeWithDims(baseType, numRows, 1);
}
else if (numCols >= 2)
{
// For example, convert a float3 into a float
ret.nativeType = baseType;
}
else
{
// If we don't know the type, fail silently and keep the type.
ret.nativeType = baseType;
}
}
}
break;
// these ops are not supported now, but really should be at some point;
case HlslOp.FunctionalCast: // int()
ret = HlslTree.FullTypeInfo.MakeInvalid();
break;
case HlslOp.FunctionalCall: // func()
// lhs node is the function call prototype node id, so we actually just use lhs
ret = fullTypeInfo[nodeExpression.lhsNodeId];
break;
case HlslOp.MemberAccess: // .
{
HlslTree.Node nodeRhs = allNodes[nodeExpression.rhsNodeId];
if (nodeRhs is HlslTree.NodeMemberVariable nodeMemberVariable)
{
// use this field
ret = fullTypeInfo[nodeExpression.rhsNodeId];
}
else if (nodeRhs is HlslTree.NodeMemberFunction nodeMemberFunction)
{
// use the return type of the member function
ret = fullTypeInfo[nodeExpression.rhsNodeId];
}
else if (nodeRhs is HlslTree.NodeSwizzle nodeSwizzle)
{
// swizle
HlslNativeType lhsType = fullTypeInfo[nodeExpression.lhsNodeId].nativeType;
HlslNativeType baseType = HlslUtil.GetNativeBaseType(lhsType); // i.e. convert float3 to just float
HlslNativeType vecType = HlslUtil.GetVectorFromBaseType(baseType, nodeSwizzle.swizzle.Length);
ret = HlslTree.FullTypeInfo.MakeNativeType(vecType);
}
else
{
// should never happen, since these are the only 3 nodes allowed
HlslUtil.ParserAssert(false);
}
}
break;
case HlslOp.CStyleCast: // (int)
// get the struct id
if (nodeExpression.cstyleCastStructId >= 0)
{
// if the cstyle structId is >= 0, then we use this struct
HlslUtil.StructInfo structInfo = GetStructInfoFromNodeId(nodeExpression.cstyleCastStructId, unityReserved);
ret = HlslTree.FullTypeInfo.MakeStruct(structInfo.identifier, nodeExpression.cstyleCastStructId, false);
}
else
{
HlslToken tokenType = tokenizer.GetTokenType(nodeExpression.opTokenId);
HlslNativeType nativeType = HlslNativeType._invalid;
if (tokenToNativeTable.ContainsKey(tokenType))
{
nativeType = tokenToNativeTable[tokenType];
}
ret = HlslTree.FullTypeInfo.MakeNativeType(nativeType);
}
break;
case HlslOp.Sizeof: // sizeof
ret = HlslTree.FullTypeInfo.MakeNativeType(HlslNativeType._uint);
break;
// binary ops that will expand to the larger sized vector
case HlslOp.Mul: // *
case HlslOp.Div: // /
case HlslOp.Mod: // %
case HlslOp.Add: // +
case HlslOp.Sub: // -
case HlslOp.BitwiseAnd: // &
case HlslOp.BitwiseXor: // ^
case HlslOp.BitwiseOr: // |
{
HlslNativeType lhsType = fullTypeInfo[nodeExpression.lhsNodeId].nativeType;
HlslNativeType rhsType = fullTypeInfo[nodeExpression.rhsNodeId].nativeType;
bool isMul = (nodeExpression.op == HlslOp.Mul);
HlslNativeType dstType = HlslUtil.GetBinaryOpReturnType(lhsType, rhsType, isMul);
ret = HlslTree.FullTypeInfo.MakeNativeType(dstType);
}
break;
// comparison ops that will expand to the larger sized vector but convert to bool
case HlslOp.LessThan: // <
case HlslOp.GreaterThan: // >
case HlslOp.LessEqual: // <=
case HlslOp.GreaterEqual: // >=
case HlslOp.CompareEqual: // ==
case HlslOp.NotEqual: // !=
case HlslOp.LogicalAnd: // &&
case HlslOp.LogicalOr: // ||
{
HlslNativeType lhsType = fullTypeInfo[nodeExpression.lhsNodeId].nativeType;
HlslNativeType rhsType = fullTypeInfo[nodeExpression.rhsNodeId].nativeType;
int lhsRows = HlslUtil.GetNumRows(lhsType);
int lhsCols = HlslUtil.GetNumCols(lhsType);
int rhsRows = HlslUtil.GetNumRows(rhsType);
int rhsCols = HlslUtil.GetNumCols(rhsType);
// just use the max for now
int dstRows = Math.Max(lhsRows, rhsRows);
int dstCols = Math.Max(lhsRows, rhsRows);
HlslNativeType dstType = HlslUtil.GetBaseTypeWithDims(HlslNativeType._bool, dstRows, dstCols);
ret = HlslTree.FullTypeInfo.MakeNativeType(dstType);
}
break;
case HlslOp.TernaryQuestion: // ?
// treat this as the binary op of the middle and right terms?
{
HlslNativeType rhsType = fullTypeInfo[nodeExpression.rhsNodeId].nativeType;
HlslNativeType rhsRhsType = fullTypeInfo[nodeExpression.rhsRhsNodeId].nativeType;
HlslNativeType dstType = HlslUtil.GetBinaryOpReturnType(rhsType, rhsRhsType, false);
ret = HlslTree.FullTypeInfo.MakeNativeType(dstType);
}
break;
case HlslOp.TernaryColon: // :
// should never happen, since the three terms of the ternary are grouped into a single expression
// with op as HlslOp.TernaryQuestion
break;
case HlslOp.Comma: // ,
// simply returns rhs
ret = fullTypeInfo[nodeExpression.rhsNodeId];
break;
default:
break;
}
return ret;
}
HlslTree.FullTypeInfo GetFullTypeInfoFromParserInfoAndDims(HlslParser.TypeInfo parserTypeInfo, int dims)
{
HlslTree.FullTypeInfo ret = GetFullTypeInfoFromParserInfo(parserTypeInfo);
ret.arrayDims = dims;
return ret;
}
// assumes that the children have been resolved
internal HlslTree.FullTypeInfo ResolveFullTypeForNode(int nodeId)
{
HlslTree.FullTypeInfo ret = new HlslTree.FullTypeInfo();
HlslTree.Node baseNode = allNodes[nodeId];
if (baseNode is HlslTree.NodeTopLevel nodeTopLevel)
{
ret = HlslTree.FullTypeInfo.MakeValidNoType();
}
else if (baseNode is HlslTree.NodeStruct nodeStruct)
{
HlslUtil.StructInfo structInfo = GetStructInfoFromNodeId(nodeId, unityReserved);
ret = HlslTree.FullTypeInfo.MakeStruct(structInfo.identifier, nodeStruct.structInfoId, false);
}
else if (baseNode is HlslTree.NodeUnityStruct nodeUnityStruct)
{
HlslUtil.StructInfo structInfo = GetStructInfoFromNodeId(nodeId, unityReserved);
ret = HlslTree.FullTypeInfo.MakeStruct(structInfo.identifier, -1, true);
}
else if (baseNode is HlslTree.NodeFunctionPrototype nodeFunctionPrototype)
{
HlslUtil.PrototypeInfo protoInfo = parsedFuncStructData.allPrototypes[nodeFunctionPrototype.protoId];
ret = GetFullTypeInfoFromParserInfo(protoInfo.returnType);
}
else if (baseNode is HlslTree.NodeFunctionPrototypeExternal nodeFunctionPrototypeExternal)
{
HlslUtil.PrototypeInfo protoInfo = nodeFunctionPrototypeExternal.protoInfo;
ret = GetFullTypeInfoFromParserInfo(protoInfo.returnType);
}
else if (baseNode is HlslTree.NodeBlock nodeBlock)
{
ret = HlslTree.FullTypeInfo.MakeValidNoType();
}
else if (baseNode is HlslTree.NodeStatement nodeStatement)
{
HlslTree.FullTypeInfo dstType = HlslTree.FullTypeInfo.MakeValidNoType();
switch (nodeStatement.type)
{
case HlslStatementType.If:
break;
case HlslStatementType.Switch:
break;
case HlslStatementType.Case:
break;
case HlslStatementType.Break:
break;
case HlslStatementType.Continue:
break;
case HlslStatementType.Default:
break;
case HlslStatementType.Goto:
break;
case HlslStatementType.Label:
break;
case HlslStatementType.For:
break;
case HlslStatementType.Do:
break;
case HlslStatementType.While:
break;
case HlslStatementType.Expression:
break;
case HlslStatementType.Return:
break;
default:
HlslUtil.ParserAssert(false);
break;
}
ret = dstType;
}
else if (baseNode is HlslTree.NodeFunction nodeFunction)
{
ret = fullTypeInfo[nodeFunction.prototypeId];
}
else if (baseNode is HlslTree.NodeDeclaration nodeDeclaration)
{
if (nodeDeclaration.structId >= 0)
{
HlslTree.Node typeNode = allNodes[nodeDeclaration.typeNodeId];
if (typeNode is HlslTree.NodeToken nodeToken)
{
string identifier = tokenizer.GetTokenData(nodeToken.srcTokenId);
bool isUnityBuiltin = IsStructUnityBuiltin(nodeDeclaration.structId);
ret = FullTypeInfo.MakeStruct(identifier, nodeDeclaration.structId, isUnityBuiltin);
}
else
{
ret = fullTypeInfo[nodeDeclaration.typeNodeId];
}
}
else
{
ret = fullTypeInfo[nodeDeclaration.typeNodeId];
}
ret.arrayDims = nodeDeclaration.arrayDims.Length;
//tree.fullTypeInfo[nodeId] = tree.fullTypeInfo[nodeDeclaration.typeNodeId];
//tree.fullTypeInfo[nodeId].arrayDims = nodeDeclaration.arrayDims.Length;
}
else if (baseNode is HlslTree.NodeVariable nodeVariable)
{
if (nodeVariable.nameVariableId >= 0)
{
// if it's a variable defined in this code, fetch it
HlslParser.TypeInfo typeInfo = nodeVariable.GetNodeTypeInfo(this);
ret = GetFullTypeInfoFromParserInfo(typeInfo);
}
else
{
// otherwise, it must be a reserved gloval
HlslParser.TypeInfo typeInfo;
string identifier = tokenizer.GetTokenData(nodeVariable.nameTokenId);
bool found = unityReserved.FindUnityGlobal(out typeInfo, identifier);
HlslUtil.ParserAssert(found);
ret = GetFullTypeInfoFromParserInfo(typeInfo);
}
}
else if (baseNode is HlslTree.NodeNativeConstructor nodeNativeConstructor)
{
HlslParser.TypeInfo typeInfo = nodeNativeConstructor.GetNodeTypeInfo(this);
ret = GetFullTypeInfoFromParserInfo(typeInfo);
}
else if (baseNode is HlslTree.NodeToken nodeToken)
{
ret = GetFullTypeInfoFromRawTokenId(nodeToken.srcTokenId);
}
else if (baseNode is HlslTree.NodeNativeType nodeNativeType)
{
ret = HlslTree.FullTypeInfo.MakeNativeType(nodeNativeType.nativeType);
}
else if (baseNode is HlslTree.NodeLiteralOrBool nodeLiteralOrBool)
{
HlslTree.FullTypeInfo fullInfo = HlslTree.FullTypeInfo.MakeInvalid();
HlslToken tokenType = tokenizer.GetTokenType(nodeLiteralOrBool.nameTokenId);
switch (tokenType)
{
case HlslToken._literal_float:
fullInfo = HlslTree.FullTypeInfo.MakeNativeType(HlslNativeType._float);
break;
case HlslToken._literal_half:
fullInfo = HlslTree.FullTypeInfo.MakeNativeType(HlslNativeType._half);
break;
case HlslToken._literal_int:
fullInfo = HlslTree.FullTypeInfo.MakeNativeType(HlslNativeType._int);
break;
case HlslToken._literal_uint:
fullInfo = HlslTree.FullTypeInfo.MakeNativeType(HlslNativeType._uint);
break;
case HlslToken._literal_double:
// we don't really support doubles yet. float instead?
fullInfo = HlslTree.FullTypeInfo.MakeNativeType(HlslNativeType._float);
break;
case HlslToken._true:
case HlslToken._false:
fullInfo = HlslTree.FullTypeInfo.MakeNativeType(HlslNativeType._bool);
break;
default:
// no op, leave fullInfo as invalid
break;
}
ret = fullInfo;
}
else if (baseNode is HlslTree.NodePassthrough nodePassthrough)
{
// we are passing through the text without understanding it, so no type
ret = HlslTree.FullTypeInfo.MakeValidNoType();
}
else if (baseNode is HlslTree.NodeExpression nodeExpression)
{
ret = ResolveExpressionType(nodeExpression);
}
else if (baseNode is HlslTree.NodeMemberVariable nodeMemberVariable)
{
HlslUtil.StructInfo structInfo = GetStructInfoFromNodeId(nodeMemberVariable.structNodeId, unityReserved);
HlslUtil.FieldInfo fieldInfo = structInfo.fields[nodeMemberVariable.fieldIndex];
ret = GetFullTypeInfoFromParserInfoAndDims(fieldInfo.typeInfo, fieldInfo.arrayDims);
}
else if (baseNode is HlslTree.NodeParenthesisGroup nodeParenthesisGroup)
{
if (nodeParenthesisGroup.childNodeId < 0)
{
HlslUtil.ParserAssert(false);
}
ret = fullTypeInfo[nodeParenthesisGroup.childNodeId];
}
else if (baseNode is HlslTree.NodeMemberFunction nodeMemberFunction)
{
HlslUtil.StructInfo structInfo = GetStructInfoFromNodeId(nodeMemberFunction.structNodeId, unityReserved);
HlslUtil.PrototypeInfo protoInfo = structInfo.prototypes[nodeMemberFunction.funcIndex];
ret = GetFullTypeInfoFromParserInfo(protoInfo.returnType);
}
else if (baseNode is HlslTree.NodeSwizzle nodeSwizzle)
{
// the swizzle doesn't have a type per se. The expression node above it has both the
// lhsNode, and the swizzle as children, so the that expression will apply the swizzle
// to the type
ret = HlslTree.FullTypeInfo.MakeValidNoType();
}
else if (baseNode is HlslTree.NodeBlockInitializer)
{
// we could store types, but it would be a pain. for now just ignore them.
ret = HlslTree.FullTypeInfo.MakeValidNoType();
}
else
{
// if we got here, then we are missing a type in this if tree
HlslUtil.ParserAssert(false);
}
return ret;
}
HlslUnityReserved unityReserved;
HlslTokenizer tokenizer;
internal Dictionary<HlslToken, HlslNativeType> tokenToNativeTable;
// These are prototypes for builtin functions, unity reserved identifiers, or other
// included functions that are actually used but we won't actually declare in the shader text.
internal List<Node> prototypesReserved;
internal HlslUtil.ParsedFuncStructData parsedFuncStructData;
internal List<Node> allNodes;
internal int topLevelNode;
internal List<FullTypeInfo> fullTypeInfo;
internal List<ErrInfo> errList;
internal List<Dictionary<string, int>> structLookupStack; // lookup from string -> struct identifier
internal List<VariableInfo> allVariables;
internal List<Dictionary<string, int>> variableLookupStack;
}
}