Shader: Add support for compound operators
This commit is contained in:
parent
601ed047ba
commit
0442db1c53
|
|
@ -48,10 +48,10 @@ fn main(input: FragIn) -> FragOut
|
||||||
let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize * 10.0;
|
let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize * 10.0;
|
||||||
|
|
||||||
let color = colorTexture.Sample(fragcoord).rgb;
|
let color = colorTexture.Sample(fragcoord).rgb;
|
||||||
color = color * (BrightMiddleGrey/BrightLuminance);
|
color *= BrightMiddleGrey / BrightLuminance;
|
||||||
color = color * (vec3<f32>(1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold)));
|
color *= vec3<f32>(1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold));
|
||||||
color = color - vec3<f32>(0.5, 0.5, 0.5);
|
color -= vec3<f32>(0.5, 0.5, 0.5);
|
||||||
color = color / (vec3<f32>(1.0, 1.0, 1.0) + color);
|
color /= vec3<f32>(1.0, 1.0, 1.0) + color;
|
||||||
|
|
||||||
let output: FragOut;
|
let output: FragOut;
|
||||||
output.color = vec4<f32>(color, 1.0);
|
output.color = vec4<f32>(color, 1.0);
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,7 @@ fn main(input: InputData) -> OutputData
|
||||||
{
|
{
|
||||||
let diffuseColor = settings.DiffuseColor;
|
let diffuseColor = settings.DiffuseColor;
|
||||||
const if (HasDiffuseTexture)
|
const if (HasDiffuseTexture)
|
||||||
// TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv)
|
diffuseColor *= MaterialDiffuseMap.Sample(input.uv);
|
||||||
diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv);
|
|
||||||
|
|
||||||
const if (HasAlphaTexture)
|
const if (HasAlphaTexture)
|
||||||
// TODO: diffuseColor.w *= MaterialAlphaMap.Sample(input.uv)).x
|
// TODO: diffuseColor.w *= MaterialAlphaMap.Sample(input.uv)).x
|
||||||
|
|
|
||||||
|
|
@ -48,19 +48,19 @@ fn main(input: FragIn) -> FragOut
|
||||||
|
|
||||||
let filter = vec2<f32>(1.0, 0.0);
|
let filter = vec2<f32>(1.0, 0.0);
|
||||||
|
|
||||||
color = color + colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
|
color += colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
|
||||||
color = color + colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
|
color += colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
|
||||||
|
|
||||||
color = color + colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
|
color += colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
|
||||||
color = color + colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
|
color += colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
|
||||||
|
|
||||||
filter = vec2<f32>(0.0, 1.0);
|
filter = vec2<f32>(0.0, 1.0);
|
||||||
|
|
||||||
color = color + colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
|
color += colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
|
||||||
color = color + colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
|
color += colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
|
||||||
|
|
||||||
color = color + colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
|
color += colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
|
||||||
color = color + colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
|
color += colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
|
||||||
|
|
||||||
let output: FragOut;
|
let output: FragOut;
|
||||||
output.color = vec4<f32>(color, 1.0);
|
output.color = vec4<f32>(color, 1.0);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,13 @@ namespace Nz
|
||||||
{
|
{
|
||||||
enum class AssignType
|
enum class AssignType
|
||||||
{
|
{
|
||||||
Simple //< =
|
Simple, //< a = b
|
||||||
|
CompoundAdd, //< a += b
|
||||||
|
CompoundDivide, //< a /= b
|
||||||
|
CompoundMultiply, //< a *= b
|
||||||
|
CompoundLogicalAnd, //< a &&= b
|
||||||
|
CompoundLogicalOr, //< a ||= b
|
||||||
|
CompoundSubtract, //< a -= b
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class AttributeType
|
enum class AttributeType
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ namespace Nz::ShaderAst
|
||||||
std::unordered_set<std::string> reservedIdentifiers;
|
std::unordered_set<std::string> reservedIdentifiers;
|
||||||
std::unordered_map<std::size_t, ConstantValue> optionValues;
|
std::unordered_map<std::size_t, ConstantValue> optionValues;
|
||||||
bool makeVariableNameUnique = false;
|
bool makeVariableNameUnique = false;
|
||||||
|
bool removeCompoundAssignments = false;
|
||||||
bool removeOptionDeclaration = true;
|
bool removeOptionDeclaration = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -76,9 +77,9 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
const Identifier* FindIdentifier(const std::string_view& identifierName) const;
|
const Identifier* FindIdentifier(const std::string_view& identifierName) const;
|
||||||
|
|
||||||
Expression& MandatoryExpr(ExpressionPtr& node);
|
Expression& MandatoryExpr(const ExpressionPtr& node);
|
||||||
Statement& MandatoryStatement(StatementPtr& node);
|
Statement& MandatoryStatement(const StatementPtr& node);
|
||||||
void TypeMustMatch(ExpressionPtr& left, ExpressionPtr& right);
|
void TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right);
|
||||||
void TypeMustMatch(const ExpressionType& left, const ExpressionType& right);
|
void TypeMustMatch(const ExpressionType& left, const ExpressionType& right);
|
||||||
|
|
||||||
void PushScope();
|
void PushScope();
|
||||||
|
|
@ -111,6 +112,7 @@ namespace Nz::ShaderAst
|
||||||
void Validate(AccessIndexExpression& node);
|
void Validate(AccessIndexExpression& node);
|
||||||
void Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration);
|
void Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration);
|
||||||
void Validate(IntrinsicExpression& node);
|
void Validate(IntrinsicExpression& node);
|
||||||
|
ExpressionType ValidateBinaryOp(BinaryType op, const ExpressionPtr& leftExpr, const ExpressionPtr& rightExpr);
|
||||||
|
|
||||||
struct FunctionData
|
struct FunctionData
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ NAZARA_SHADERLANG_TOKEN(Const)
|
||||||
NAZARA_SHADERLANG_TOKEN(ConstSelect)
|
NAZARA_SHADERLANG_TOKEN(ConstSelect)
|
||||||
NAZARA_SHADERLANG_TOKEN(Discard)
|
NAZARA_SHADERLANG_TOKEN(Discard)
|
||||||
NAZARA_SHADERLANG_TOKEN(Divide)
|
NAZARA_SHADERLANG_TOKEN(Divide)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(DivideAssign)
|
||||||
NAZARA_SHADERLANG_TOKEN(Dot)
|
NAZARA_SHADERLANG_TOKEN(Dot)
|
||||||
NAZARA_SHADERLANG_TOKEN(Equal)
|
NAZARA_SHADERLANG_TOKEN(Equal)
|
||||||
NAZARA_SHADERLANG_TOKEN(Else)
|
NAZARA_SHADERLANG_TOKEN(Else)
|
||||||
|
|
@ -39,12 +40,17 @@ NAZARA_SHADERLANG_TOKEN(LessThan)
|
||||||
NAZARA_SHADERLANG_TOKEN(LessThanEqual)
|
NAZARA_SHADERLANG_TOKEN(LessThanEqual)
|
||||||
NAZARA_SHADERLANG_TOKEN(Let)
|
NAZARA_SHADERLANG_TOKEN(Let)
|
||||||
NAZARA_SHADERLANG_TOKEN(LogicalAnd)
|
NAZARA_SHADERLANG_TOKEN(LogicalAnd)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(LogicalAndAssign)
|
||||||
NAZARA_SHADERLANG_TOKEN(LogicalOr)
|
NAZARA_SHADERLANG_TOKEN(LogicalOr)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(LogicalOrAssign)
|
||||||
NAZARA_SHADERLANG_TOKEN(Multiply)
|
NAZARA_SHADERLANG_TOKEN(Multiply)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(MultiplyAssign)
|
||||||
NAZARA_SHADERLANG_TOKEN(Minus)
|
NAZARA_SHADERLANG_TOKEN(Minus)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(MinusAssign)
|
||||||
NAZARA_SHADERLANG_TOKEN(Not)
|
NAZARA_SHADERLANG_TOKEN(Not)
|
||||||
NAZARA_SHADERLANG_TOKEN(NotEqual)
|
NAZARA_SHADERLANG_TOKEN(NotEqual)
|
||||||
NAZARA_SHADERLANG_TOKEN(Plus)
|
NAZARA_SHADERLANG_TOKEN(Plus)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(PlusAssign)
|
||||||
NAZARA_SHADERLANG_TOKEN(OpenCurlyBracket)
|
NAZARA_SHADERLANG_TOKEN(OpenCurlyBracket)
|
||||||
NAZARA_SHADERLANG_TOKEN(OpenSquareBracket)
|
NAZARA_SHADERLANG_TOKEN(OpenSquareBracket)
|
||||||
NAZARA_SHADERLANG_TOKEN(OpenParenthesis)
|
NAZARA_SHADERLANG_TOKEN(OpenParenthesis)
|
||||||
|
|
|
||||||
|
|
@ -66,16 +66,13 @@ fn main(input: FragIn) -> FragOut
|
||||||
let diffuseColor = settings.DiffuseColor;
|
let diffuseColor = settings.DiffuseColor;
|
||||||
|
|
||||||
const if (HasUV)
|
const if (HasUV)
|
||||||
//TODO: diffuseColor *= TextureOverlay.Sample(input.uv);
|
diffuseColor *= TextureOverlay.Sample(input.uv);
|
||||||
diffuseColor = diffuseColor * TextureOverlay.Sample(input.uv);
|
|
||||||
|
|
||||||
const if (HasVertexColor)
|
const if (HasVertexColor)
|
||||||
//TODO: diffuseColor *= input.color;
|
diffuseColor *= input.color;
|
||||||
diffuseColor = diffuseColor * input.color;
|
|
||||||
|
|
||||||
const if (HasDiffuseTexture)
|
const if (HasDiffuseTexture)
|
||||||
// TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv)
|
diffuseColor *= MaterialDiffuseMap.Sample(input.uv);
|
||||||
diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv);
|
|
||||||
|
|
||||||
const if (HasAlphaTexture)
|
const if (HasAlphaTexture)
|
||||||
// TODO: diffuseColor.w *= MaterialAlphaMap.Sample(input.uv)).x
|
// TODO: diffuseColor.w *= MaterialAlphaMap.Sample(input.uv)).x
|
||||||
|
|
|
||||||
|
|
@ -54,16 +54,13 @@ fn main(input: FragIn)
|
||||||
let alpha = settings.DiffuseColor.a;
|
let alpha = settings.DiffuseColor.a;
|
||||||
|
|
||||||
const if (HasUV)
|
const if (HasUV)
|
||||||
//TODO: diffuseColor *= TextureOverlay.Sample(input.uv);
|
alpha *= TextureOverlay.Sample(input.uv).a;
|
||||||
alpha = alpha * TextureOverlay.Sample(input.uv).a;
|
|
||||||
|
|
||||||
const if (HasDiffuseTexture)
|
const if (HasDiffuseTexture)
|
||||||
// TODO: alpha *= MaterialDiffuseMap.Sample(input.uv).a;
|
alpha *= MaterialDiffuseMap.Sample(input.uv).a;
|
||||||
alpha = alpha * MaterialDiffuseMap.Sample(input.uv).a;
|
|
||||||
|
|
||||||
const if (HasAlphaTexture)
|
const if (HasAlphaTexture)
|
||||||
// TODO: alpha *= MaterialAlphaMap.Sample(input.uv).x
|
alpha *= MaterialAlphaMap.Sample(input.uv).x;
|
||||||
alpha = alpha * MaterialAlphaMap.Sample(input.uv).x;
|
|
||||||
|
|
||||||
if (alpha < settings.AlphaThreshold)
|
if (alpha < settings.AlphaThreshold)
|
||||||
discard;
|
discard;
|
||||||
|
|
|
||||||
|
|
@ -253,8 +253,35 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
auto clone = static_unique_pointer_cast<AssignExpression>(AstCloner::Clone(node));
|
auto clone = static_unique_pointer_cast<AssignExpression>(AstCloner::Clone(node));
|
||||||
|
|
||||||
TypeMustMatch(clone->left, clone->right);
|
std::optional<BinaryType> binaryType;
|
||||||
clone->cachedExpressionType = GetExpressionType(*clone->right);
|
switch (clone->op)
|
||||||
|
{
|
||||||
|
case AssignType::Simple:
|
||||||
|
TypeMustMatch(clone->left, clone->right);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AssignType::CompoundAdd: binaryType = BinaryType::Add; break;
|
||||||
|
case AssignType::CompoundDivide: binaryType = BinaryType::Divide; break;
|
||||||
|
case AssignType::CompoundMultiply: binaryType = BinaryType::Multiply; break;
|
||||||
|
case AssignType::CompoundLogicalAnd: binaryType = BinaryType::LogicalAnd; break;
|
||||||
|
case AssignType::CompoundLogicalOr: binaryType = BinaryType::LogicalOr; break;
|
||||||
|
case AssignType::CompoundSubtract: binaryType = BinaryType::Subtract; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binaryType)
|
||||||
|
{
|
||||||
|
ExpressionType expressionType = ValidateBinaryOp(*binaryType, clone->left, clone->right);
|
||||||
|
TypeMustMatch(GetExpressionType(*clone->left), expressionType);
|
||||||
|
|
||||||
|
if (m_context->options.removeCompoundAssignments)
|
||||||
|
{
|
||||||
|
clone->op = AssignType::Simple;
|
||||||
|
clone->right = ShaderBuilder::Binary(*binaryType, AstCloner::Clone(*clone->left), std::move(clone->right));
|
||||||
|
clone->right->cachedExpressionType = std::move(expressionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clone->cachedExpressionType = GetExpressionType(*clone->left);
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
@ -262,191 +289,7 @@ namespace Nz::ShaderAst
|
||||||
ExpressionPtr SanitizeVisitor::Clone(BinaryExpression& node)
|
ExpressionPtr SanitizeVisitor::Clone(BinaryExpression& node)
|
||||||
{
|
{
|
||||||
auto clone = static_unique_pointer_cast<BinaryExpression>(AstCloner::Clone(node));
|
auto clone = static_unique_pointer_cast<BinaryExpression>(AstCloner::Clone(node));
|
||||||
|
clone->cachedExpressionType = ValidateBinaryOp(clone->op, clone->left, clone->right);
|
||||||
const ExpressionType& leftExprType = GetExpressionType(MandatoryExpr(clone->left));
|
|
||||||
if (!IsPrimitiveType(leftExprType) && !IsMatrixType(leftExprType) && !IsVectorType(leftExprType))
|
|
||||||
throw AstError{ "left expression type does not support binary operation" };
|
|
||||||
|
|
||||||
const ExpressionType& rightExprType = GetExpressionType(MandatoryExpr(clone->right));
|
|
||||||
if (!IsPrimitiveType(rightExprType) && !IsMatrixType(rightExprType) && !IsVectorType(rightExprType))
|
|
||||||
throw AstError{ "right expression type does not support binary operation" };
|
|
||||||
|
|
||||||
if (IsPrimitiveType(leftExprType))
|
|
||||||
{
|
|
||||||
PrimitiveType leftType = std::get<PrimitiveType>(leftExprType);
|
|
||||||
switch (clone->op)
|
|
||||||
{
|
|
||||||
case BinaryType::CompGe:
|
|
||||||
case BinaryType::CompGt:
|
|
||||||
case BinaryType::CompLe:
|
|
||||||
case BinaryType::CompLt:
|
|
||||||
if (leftType == PrimitiveType::Boolean)
|
|
||||||
throw AstError{ "this operation is not supported for booleans" };
|
|
||||||
|
|
||||||
TypeMustMatch(clone->left, clone->right);
|
|
||||||
|
|
||||||
clone->cachedExpressionType = PrimitiveType::Boolean;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BinaryType::Add:
|
|
||||||
case BinaryType::CompEq:
|
|
||||||
case BinaryType::CompNe:
|
|
||||||
case BinaryType::Subtract:
|
|
||||||
TypeMustMatch(clone->left, clone->right);
|
|
||||||
|
|
||||||
clone->cachedExpressionType = leftExprType;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BinaryType::Multiply:
|
|
||||||
case BinaryType::Divide:
|
|
||||||
{
|
|
||||||
switch (leftType)
|
|
||||||
{
|
|
||||||
case PrimitiveType::Float32:
|
|
||||||
case PrimitiveType::Int32:
|
|
||||||
case PrimitiveType::UInt32:
|
|
||||||
{
|
|
||||||
if (IsMatrixType(rightExprType))
|
|
||||||
{
|
|
||||||
TypeMustMatch(leftType, std::get<MatrixType>(rightExprType).type);
|
|
||||||
clone->cachedExpressionType = rightExprType;
|
|
||||||
}
|
|
||||||
else if (IsPrimitiveType(rightExprType))
|
|
||||||
{
|
|
||||||
TypeMustMatch(leftType, rightExprType);
|
|
||||||
clone->cachedExpressionType = leftExprType;
|
|
||||||
}
|
|
||||||
else if (IsVectorType(rightExprType))
|
|
||||||
{
|
|
||||||
TypeMustMatch(leftType, std::get<VectorType>(rightExprType).type);
|
|
||||||
clone->cachedExpressionType = rightExprType;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw AstError{ "incompatible types" };
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PrimitiveType::Boolean:
|
|
||||||
throw AstError{ "this operation is not supported for booleans" };
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw AstError{ "incompatible types" };
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BinaryType::LogicalAnd:
|
|
||||||
case BinaryType::LogicalOr:
|
|
||||||
if (leftType != PrimitiveType::Boolean)
|
|
||||||
throw AstError{ "logical and/or are only supported on booleans" };
|
|
||||||
|
|
||||||
TypeMustMatch(clone->left, clone->right);
|
|
||||||
|
|
||||||
clone->cachedExpressionType = PrimitiveType::Boolean;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IsMatrixType(leftExprType))
|
|
||||||
{
|
|
||||||
const MatrixType& leftType = std::get<MatrixType>(leftExprType);
|
|
||||||
switch (clone->op)
|
|
||||||
{
|
|
||||||
case BinaryType::CompGe:
|
|
||||||
case BinaryType::CompGt:
|
|
||||||
case BinaryType::CompLe:
|
|
||||||
case BinaryType::CompLt:
|
|
||||||
case BinaryType::CompEq:
|
|
||||||
case BinaryType::CompNe:
|
|
||||||
TypeMustMatch(clone->left, clone->right);
|
|
||||||
clone->cachedExpressionType = PrimitiveType::Boolean;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BinaryType::Add:
|
|
||||||
case BinaryType::Subtract:
|
|
||||||
TypeMustMatch(clone->left, clone->right);
|
|
||||||
clone->cachedExpressionType = leftExprType;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BinaryType::Multiply:
|
|
||||||
case BinaryType::Divide:
|
|
||||||
{
|
|
||||||
if (IsMatrixType(rightExprType))
|
|
||||||
{
|
|
||||||
TypeMustMatch(leftExprType, rightExprType);
|
|
||||||
clone->cachedExpressionType = leftExprType; //< FIXME
|
|
||||||
}
|
|
||||||
else if (IsPrimitiveType(rightExprType))
|
|
||||||
{
|
|
||||||
TypeMustMatch(leftType.type, rightExprType);
|
|
||||||
clone->cachedExpressionType = leftExprType;
|
|
||||||
}
|
|
||||||
else if (IsVectorType(rightExprType))
|
|
||||||
{
|
|
||||||
const VectorType& rightType = std::get<VectorType>(rightExprType);
|
|
||||||
TypeMustMatch(leftType.type, rightType.type);
|
|
||||||
|
|
||||||
if (leftType.columnCount != rightType.componentCount)
|
|
||||||
throw AstError{ "incompatible types" };
|
|
||||||
|
|
||||||
clone->cachedExpressionType = rightExprType;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw AstError{ "incompatible types" };
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BinaryType::LogicalAnd:
|
|
||||||
case BinaryType::LogicalOr:
|
|
||||||
throw AstError{ "logical and/or are only supported on booleans" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IsVectorType(leftExprType))
|
|
||||||
{
|
|
||||||
const VectorType& leftType = std::get<VectorType>(leftExprType);
|
|
||||||
switch (clone->op)
|
|
||||||
{
|
|
||||||
case BinaryType::CompGe:
|
|
||||||
case BinaryType::CompGt:
|
|
||||||
case BinaryType::CompLe:
|
|
||||||
case BinaryType::CompLt:
|
|
||||||
case BinaryType::CompEq:
|
|
||||||
case BinaryType::CompNe:
|
|
||||||
TypeMustMatch(clone->left, clone->right);
|
|
||||||
clone->cachedExpressionType = PrimitiveType::Boolean;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BinaryType::Add:
|
|
||||||
case BinaryType::Subtract:
|
|
||||||
TypeMustMatch(clone->left, clone->right);
|
|
||||||
clone->cachedExpressionType = leftExprType;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BinaryType::Multiply:
|
|
||||||
case BinaryType::Divide:
|
|
||||||
{
|
|
||||||
if (IsPrimitiveType(rightExprType))
|
|
||||||
{
|
|
||||||
TypeMustMatch(leftType.type, rightExprType);
|
|
||||||
clone->cachedExpressionType = leftExprType;
|
|
||||||
}
|
|
||||||
else if (IsVectorType(rightExprType))
|
|
||||||
{
|
|
||||||
TypeMustMatch(leftType, rightExprType);
|
|
||||||
clone->cachedExpressionType = rightExprType;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw AstError{ "incompatible types" };
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BinaryType::LogicalAnd:
|
|
||||||
case BinaryType::LogicalOr:
|
|
||||||
throw AstError{ "logical and/or are only supported on booleans" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
@ -1116,7 +959,7 @@ namespace Nz::ShaderAst
|
||||||
return &*it;
|
return &*it;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression& SanitizeVisitor::MandatoryExpr(ExpressionPtr& node)
|
Expression& SanitizeVisitor::MandatoryExpr(const ExpressionPtr& node)
|
||||||
{
|
{
|
||||||
if (!node)
|
if (!node)
|
||||||
throw AstError{ "Invalid expression" };
|
throw AstError{ "Invalid expression" };
|
||||||
|
|
@ -1124,7 +967,7 @@ namespace Nz::ShaderAst
|
||||||
return *node;
|
return *node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement& SanitizeVisitor::MandatoryStatement(StatementPtr& node)
|
Statement& SanitizeVisitor::MandatoryStatement(const StatementPtr& node)
|
||||||
{
|
{
|
||||||
if (!node)
|
if (!node)
|
||||||
throw AstError{ "Invalid statement" };
|
throw AstError{ "Invalid statement" };
|
||||||
|
|
@ -1640,7 +1483,189 @@ namespace Nz::ShaderAst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SanitizeVisitor::TypeMustMatch(ExpressionPtr& left, ExpressionPtr& right)
|
ExpressionType SanitizeVisitor::ValidateBinaryOp(BinaryType op, const ExpressionPtr& leftExpr, const ExpressionPtr& rightExpr)
|
||||||
|
{
|
||||||
|
const ExpressionType& leftExprType = GetExpressionType(MandatoryExpr(leftExpr));
|
||||||
|
const ExpressionType& rightExprType = GetExpressionType(MandatoryExpr(rightExpr));
|
||||||
|
|
||||||
|
if (!IsPrimitiveType(leftExprType) && !IsMatrixType(leftExprType) && !IsVectorType(leftExprType))
|
||||||
|
throw AstError{ "left expression type does not support binary operation" };
|
||||||
|
|
||||||
|
if (!IsPrimitiveType(rightExprType) && !IsMatrixType(rightExprType) && !IsVectorType(rightExprType))
|
||||||
|
throw AstError{ "right expression type does not support binary operation" };
|
||||||
|
|
||||||
|
if (IsPrimitiveType(leftExprType))
|
||||||
|
{
|
||||||
|
PrimitiveType leftType = std::get<PrimitiveType>(leftExprType);
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case BinaryType::CompGe:
|
||||||
|
case BinaryType::CompGt:
|
||||||
|
case BinaryType::CompLe:
|
||||||
|
case BinaryType::CompLt:
|
||||||
|
{
|
||||||
|
if (leftType == PrimitiveType::Boolean)
|
||||||
|
throw AstError{ "this operation is not supported for booleans" };
|
||||||
|
|
||||||
|
TypeMustMatch(leftExpr, rightExpr);
|
||||||
|
return PrimitiveType::Boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BinaryType::Add:
|
||||||
|
case BinaryType::CompEq:
|
||||||
|
case BinaryType::CompNe:
|
||||||
|
case BinaryType::Subtract:
|
||||||
|
TypeMustMatch(leftExpr, rightExpr);
|
||||||
|
return leftExprType;
|
||||||
|
|
||||||
|
case BinaryType::Multiply:
|
||||||
|
case BinaryType::Divide:
|
||||||
|
{
|
||||||
|
switch (leftType)
|
||||||
|
{
|
||||||
|
case PrimitiveType::Float32:
|
||||||
|
case PrimitiveType::Int32:
|
||||||
|
case PrimitiveType::UInt32:
|
||||||
|
{
|
||||||
|
if (IsMatrixType(rightExprType))
|
||||||
|
{
|
||||||
|
TypeMustMatch(leftType, std::get<MatrixType>(rightExprType).type);
|
||||||
|
return rightExprType;
|
||||||
|
}
|
||||||
|
else if (IsPrimitiveType(rightExprType))
|
||||||
|
{
|
||||||
|
TypeMustMatch(leftType, rightExprType);
|
||||||
|
return leftExprType;
|
||||||
|
}
|
||||||
|
else if (IsVectorType(rightExprType))
|
||||||
|
{
|
||||||
|
TypeMustMatch(leftType, std::get<VectorType>(rightExprType).type);
|
||||||
|
return rightExprType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw AstError{ "incompatible types" };
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PrimitiveType::Boolean:
|
||||||
|
throw AstError{ "this operation is not supported for booleans" };
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw AstError{ "incompatible types" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case BinaryType::LogicalAnd:
|
||||||
|
case BinaryType::LogicalOr:
|
||||||
|
{
|
||||||
|
if (leftType != PrimitiveType::Boolean)
|
||||||
|
throw AstError{ "logical and/or are only supported on booleans" };
|
||||||
|
|
||||||
|
TypeMustMatch(leftExpr, rightExpr);
|
||||||
|
return PrimitiveType::Boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (IsMatrixType(leftExprType))
|
||||||
|
{
|
||||||
|
const MatrixType& leftType = std::get<MatrixType>(leftExprType);
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case BinaryType::CompGe:
|
||||||
|
case BinaryType::CompGt:
|
||||||
|
case BinaryType::CompLe:
|
||||||
|
case BinaryType::CompLt:
|
||||||
|
case BinaryType::CompEq:
|
||||||
|
case BinaryType::CompNe:
|
||||||
|
TypeMustMatch(leftExpr, rightExpr);
|
||||||
|
return PrimitiveType::Boolean;
|
||||||
|
|
||||||
|
case BinaryType::Add:
|
||||||
|
case BinaryType::Subtract:
|
||||||
|
TypeMustMatch(leftExpr, rightExpr);
|
||||||
|
return leftExprType;
|
||||||
|
|
||||||
|
case BinaryType::Multiply:
|
||||||
|
case BinaryType::Divide:
|
||||||
|
{
|
||||||
|
if (IsMatrixType(rightExprType))
|
||||||
|
{
|
||||||
|
TypeMustMatch(leftExprType, rightExprType);
|
||||||
|
return leftExprType; //< FIXME
|
||||||
|
}
|
||||||
|
else if (IsPrimitiveType(rightExprType))
|
||||||
|
{
|
||||||
|
TypeMustMatch(leftType.type, rightExprType);
|
||||||
|
return leftExprType;
|
||||||
|
}
|
||||||
|
else if (IsVectorType(rightExprType))
|
||||||
|
{
|
||||||
|
const VectorType& rightType = std::get<VectorType>(rightExprType);
|
||||||
|
TypeMustMatch(leftType.type, rightType.type);
|
||||||
|
|
||||||
|
if (leftType.columnCount != rightType.componentCount)
|
||||||
|
throw AstError{ "incompatible types" };
|
||||||
|
|
||||||
|
return rightExprType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw AstError{ "incompatible types" };
|
||||||
|
}
|
||||||
|
|
||||||
|
case BinaryType::LogicalAnd:
|
||||||
|
case BinaryType::LogicalOr:
|
||||||
|
throw AstError{ "logical and/or are only supported on booleans" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (IsVectorType(leftExprType))
|
||||||
|
{
|
||||||
|
const VectorType& leftType = std::get<VectorType>(leftExprType);
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case BinaryType::CompGe:
|
||||||
|
case BinaryType::CompGt:
|
||||||
|
case BinaryType::CompLe:
|
||||||
|
case BinaryType::CompLt:
|
||||||
|
case BinaryType::CompEq:
|
||||||
|
case BinaryType::CompNe:
|
||||||
|
TypeMustMatch(leftExpr, rightExpr);
|
||||||
|
return PrimitiveType::Boolean;
|
||||||
|
|
||||||
|
case BinaryType::Add:
|
||||||
|
case BinaryType::Subtract:
|
||||||
|
TypeMustMatch(leftExpr, rightExpr);
|
||||||
|
return leftExprType;
|
||||||
|
|
||||||
|
case BinaryType::Multiply:
|
||||||
|
case BinaryType::Divide:
|
||||||
|
{
|
||||||
|
if (IsPrimitiveType(rightExprType))
|
||||||
|
{
|
||||||
|
TypeMustMatch(leftType.type, rightExprType);
|
||||||
|
return leftExprType;
|
||||||
|
}
|
||||||
|
else if (IsVectorType(rightExprType))
|
||||||
|
{
|
||||||
|
TypeMustMatch(leftType, rightExprType);
|
||||||
|
return rightExprType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw AstError{ "incompatible types" };
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BinaryType::LogicalAnd:
|
||||||
|
case BinaryType::LogicalOr:
|
||||||
|
throw AstError{ "logical and/or are only supported on booleans" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw AstError{ "internal error: unchecked operation" };
|
||||||
|
}
|
||||||
|
|
||||||
|
void SanitizeVisitor::TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right)
|
||||||
{
|
{
|
||||||
return TypeMustMatch(GetExpressionType(*left), GetExpressionType(*right));
|
return TypeMustMatch(GetExpressionType(*left), GetExpressionType(*right));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,7 @@ namespace Nz
|
||||||
ShaderAst::SanitizeVisitor::Options options;
|
ShaderAst::SanitizeVisitor::Options options;
|
||||||
options.optionValues = std::move(optionValues);
|
options.optionValues = std::move(optionValues);
|
||||||
options.makeVariableNameUnique = true;
|
options.makeVariableNameUnique = true;
|
||||||
|
options.removeCompoundAssignments = false;
|
||||||
options.reservedIdentifiers = {
|
options.reservedIdentifiers = {
|
||||||
// All reserved GLSL keywords as of GLSL ES 3.2
|
// All reserved GLSL keywords as of GLSL ES 3.2
|
||||||
"active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer", "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard", "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4", "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float", "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray", "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube", "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect", "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant", "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect", "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "isubpassInput", "isubpassInputMS", "itexture2D", "itexture2DArray", "itexture2DMS", "itexture2DMSArray", "itexture3D", "itextureBuffer", "itextureCube", "itextureCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp", "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump", "namespace", "noinline", "noperspective", "out", "output", "partition", "patch", "precise", "precision", "public", "readonly", "resource", "restrict", "return", "sample", "sampler", "sampler1D", "sampler1DArray", "sampler1DArrayShadow", "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray", "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer", "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "samplerShadow", "shared", "short", "sizeof", "smooth", "static", "struct", "subpassInput", "subpassInputMS", "subroutine", "superp", "switch", "template", "texture2D", "texture2DArray", "texture2DMS", "texture2DMSArray", "texture3D", "textureBuffer", "textureCube", "textureCubeArray", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D", "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube", "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray", "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray", "using", "usubpassInput", "usubpassInputMS", "utexture2D", "utexture2DArray", "utexture2DMS", "utexture2DMSArray", "utexture3D", "utextureBuffer", "utextureCube", "utextureCubeArray", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile", "while", "writeonly"
|
"active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer", "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard", "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4", "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float", "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray", "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube", "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect", "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant", "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect", "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "isubpassInput", "isubpassInputMS", "itexture2D", "itexture2DArray", "itexture2DMS", "itexture2DMSArray", "itexture3D", "itextureBuffer", "itextureCube", "itextureCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp", "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump", "namespace", "noinline", "noperspective", "out", "output", "partition", "patch", "precise", "precision", "public", "readonly", "resource", "restrict", "return", "sample", "sampler", "sampler1D", "sampler1DArray", "sampler1DArrayShadow", "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray", "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer", "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "samplerShadow", "shared", "short", "sizeof", "smooth", "static", "struct", "subpassInput", "subpassInputMS", "subroutine", "superp", "switch", "template", "texture2D", "texture2DArray", "texture2DMS", "texture2DMSArray", "texture3D", "textureBuffer", "textureCube", "textureCubeArray", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D", "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube", "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray", "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray", "using", "usubpassInput", "usubpassInputMS", "utexture2D", "utexture2DArray", "utexture2DMS", "utexture2DMSArray", "utexture3D", "utextureBuffer", "utextureCube", "utextureCubeArray", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile", "while", "writeonly"
|
||||||
|
|
@ -725,9 +726,13 @@ namespace Nz
|
||||||
|
|
||||||
switch (node.op)
|
switch (node.op)
|
||||||
{
|
{
|
||||||
case ShaderAst::AssignType::Simple:
|
case ShaderAst::AssignType::Simple: Append(" = "); break;
|
||||||
Append(" = ");
|
case ShaderAst::AssignType::CompoundAdd: Append(" += "); break;
|
||||||
break;
|
case ShaderAst::AssignType::CompoundDivide: Append(" /= "); break;
|
||||||
|
case ShaderAst::AssignType::CompoundMultiply: Append(" *= "); break;
|
||||||
|
case ShaderAst::AssignType::CompoundLogicalAnd: Append(" &&= "); break;
|
||||||
|
case ShaderAst::AssignType::CompoundLogicalOr: Append(" ||= "); break;
|
||||||
|
case ShaderAst::AssignType::CompoundSubtract: Append(" -= "); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
node.right->Visit(*this);
|
node.right->Visit(*this);
|
||||||
|
|
|
||||||
|
|
@ -541,9 +541,13 @@ namespace Nz
|
||||||
|
|
||||||
switch (node.op)
|
switch (node.op)
|
||||||
{
|
{
|
||||||
case ShaderAst::AssignType::Simple:
|
case ShaderAst::AssignType::Simple: Append(" = "); break;
|
||||||
Append(" = ");
|
case ShaderAst::AssignType::CompoundAdd: Append(" += "); break;
|
||||||
break;
|
case ShaderAst::AssignType::CompoundDivide: Append(" /= "); break;
|
||||||
|
case ShaderAst::AssignType::CompoundMultiply: Append(" *= "); break;
|
||||||
|
case ShaderAst::AssignType::CompoundLogicalAnd: Append(" &&= "); break;
|
||||||
|
case ShaderAst::AssignType::CompoundLogicalOr: Append(" ||= "); break;
|
||||||
|
case ShaderAst::AssignType::CompoundSubtract: Append(" -= "); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
node.right->Visit(*this);
|
node.right->Visit(*this);
|
||||||
|
|
|
||||||
|
|
@ -106,14 +106,21 @@ namespace Nz::ShaderLang
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
{
|
{
|
||||||
if (Peek() == '>')
|
char next = Peek();
|
||||||
|
if (next == '>')
|
||||||
{
|
{
|
||||||
currentPos++;
|
currentPos++;
|
||||||
tokenType = TokenType::FunctionReturn;
|
tokenType = TokenType::FunctionReturn;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (next == '=')
|
||||||
|
{
|
||||||
|
currentPos++;
|
||||||
|
tokenType = TokenType::MinusAssign;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tokenType = TokenType::Minus;
|
||||||
|
|
||||||
tokenType = TokenType::Minus;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,6 +162,11 @@ namespace Nz::ShaderLang
|
||||||
}
|
}
|
||||||
while (next != -1);
|
while (next != -1);
|
||||||
}
|
}
|
||||||
|
else if (next == '=')
|
||||||
|
{
|
||||||
|
currentPos++;
|
||||||
|
tokenType = TokenType::DivideAssign;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
tokenType = TokenType::Divide;
|
tokenType = TokenType::Divide;
|
||||||
|
|
||||||
|
|
@ -253,7 +265,14 @@ namespace Nz::ShaderLang
|
||||||
if (next == '|')
|
if (next == '|')
|
||||||
{
|
{
|
||||||
currentPos++;
|
currentPos++;
|
||||||
tokenType = TokenType::LogicalOr;
|
next = Peek();
|
||||||
|
if (next == '=')
|
||||||
|
{
|
||||||
|
currentPos++;
|
||||||
|
tokenType = TokenType::LogicalOrAssign;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tokenType = TokenType::LogicalOr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw UnrecognizedToken{}; //< TODO: Add BOR (a | b)
|
throw UnrecognizedToken{}; //< TODO: Add BOR (a | b)
|
||||||
|
|
@ -267,7 +286,14 @@ namespace Nz::ShaderLang
|
||||||
if (next == '&')
|
if (next == '&')
|
||||||
{
|
{
|
||||||
currentPos++;
|
currentPos++;
|
||||||
tokenType = TokenType::LogicalAnd;
|
next = Peek();
|
||||||
|
if (next == '=')
|
||||||
|
{
|
||||||
|
currentPos++;
|
||||||
|
tokenType = TokenType::LogicalAndAssign;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tokenType = TokenType::LogicalAnd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw UnrecognizedToken{}; //< TODO: Add BAND (a & b)
|
throw UnrecognizedToken{}; //< TODO: Add BAND (a & b)
|
||||||
|
|
@ -317,9 +343,34 @@ namespace Nz::ShaderLang
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
{
|
||||||
|
char next = Peek();
|
||||||
|
if (next == '=')
|
||||||
|
{
|
||||||
|
currentPos++;
|
||||||
|
tokenType = TokenType::PlusAssign;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tokenType = TokenType::Plus;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
{
|
||||||
|
char next = Peek();
|
||||||
|
if (next == '=')
|
||||||
|
{
|
||||||
|
currentPos++;
|
||||||
|
tokenType = TokenType::MultiplyAssign;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tokenType = TokenType::Multiply;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case '+': tokenType = TokenType::Plus; break;
|
|
||||||
case '*': tokenType = TokenType::Multiply; break;
|
|
||||||
case ':': tokenType = TokenType::Colon; break;
|
case ':': tokenType = TokenType::Colon; break;
|
||||||
case ';': tokenType = TokenType::Semicolon; break;
|
case ';': tokenType = TokenType::Semicolon; break;
|
||||||
case '.': tokenType = TokenType::Dot; break;
|
case '.': tokenType = TokenType::Dot; break;
|
||||||
|
|
|
||||||
|
|
@ -860,12 +860,32 @@ namespace Nz::ShaderLang
|
||||||
|
|
||||||
ShaderAst::ExpressionPtr Parser::ParseVariableAssignation()
|
ShaderAst::ExpressionPtr Parser::ParseVariableAssignation()
|
||||||
{
|
{
|
||||||
|
// Variable expression
|
||||||
ShaderAst::ExpressionPtr left = ParseExpression();
|
ShaderAst::ExpressionPtr left = ParseExpression();
|
||||||
Expect(Advance(), TokenType::Assign);
|
|
||||||
|
|
||||||
|
// Assignation type
|
||||||
|
ShaderAst::AssignType assignType;
|
||||||
|
|
||||||
|
switch (Peek().type)
|
||||||
|
{
|
||||||
|
case TokenType::Assign: assignType = ShaderAst::AssignType::Simple; break;
|
||||||
|
case TokenType::DivideAssign: assignType = ShaderAst::AssignType::CompoundDivide; break;
|
||||||
|
case TokenType::LogicalAndAssign: assignType = ShaderAst::AssignType::CompoundLogicalAnd; break;
|
||||||
|
case TokenType::LogicalOrAssign: assignType = ShaderAst::AssignType::CompoundLogicalOr; break;
|
||||||
|
case TokenType::MultiplyAssign: assignType = ShaderAst::AssignType::CompoundMultiply; break;
|
||||||
|
case TokenType::MinusAssign: assignType = ShaderAst::AssignType::CompoundSubtract; break;
|
||||||
|
case TokenType::PlusAssign: assignType = ShaderAst::AssignType::CompoundAdd; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw UnexpectedToken{};
|
||||||
|
}
|
||||||
|
|
||||||
|
Consume();
|
||||||
|
|
||||||
|
// Value expression
|
||||||
ShaderAst::ExpressionPtr right = ParseExpression();
|
ShaderAst::ExpressionPtr right = ParseExpression();
|
||||||
|
|
||||||
return ShaderBuilder::Assign(ShaderAst::AssignType::Simple, std::move(left), std::move(right));
|
return ShaderBuilder::Assign(assignType, std::move(left), std::move(right));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderAst::StatementPtr Parser::ParseVariableDeclaration()
|
ShaderAst::StatementPtr Parser::ParseVariableDeclaration()
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ namespace Nz
|
||||||
|
|
||||||
void SpirvAstVisitor::Visit(ShaderAst::AssignExpression& node)
|
void SpirvAstVisitor::Visit(ShaderAst::AssignExpression& node)
|
||||||
{
|
{
|
||||||
|
if (node.op != ShaderAst::AssignType::Simple)
|
||||||
|
throw std::runtime_error("unexpected assign expression (should have been removed by sanitization)");
|
||||||
|
|
||||||
UInt32 resultId = EvaluateExpression(node.right);
|
UInt32 resultId = EvaluateExpression(node.right);
|
||||||
|
|
||||||
SpirvExpressionStore storeVisitor(m_writer, *this, *m_currentBlock);
|
SpirvExpressionStore storeVisitor(m_writer, *this, *m_currentBlock);
|
||||||
|
|
|
||||||
|
|
@ -464,6 +464,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
ShaderAst::SanitizeVisitor::Options options;
|
ShaderAst::SanitizeVisitor::Options options;
|
||||||
options.optionValues = states.optionValues;
|
options.optionValues = states.optionValues;
|
||||||
|
options.removeCompoundAssignments = true;
|
||||||
|
|
||||||
sanitizedAst = ShaderAst::Sanitize(shader, options);
|
sanitizedAst = ShaderAst::Sanitize(shader, options);
|
||||||
targetAst = sanitizedAst.get();
|
targetAst = sanitizedAst.get();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue