internal static Variable FromConstant(SSLParser.ConstantStatementContext ctx, SSLVisitor vis)
        {
            var name = ctx.Name.Text;

            if (name[0] == '$')
            {
                vis.Error(ctx, "Cannot start a variable with the character '$', this is reserved for built-in variables.");
            }
            if (name.Length > 32)
            {
                vis.Error(ctx, "Variable names cannot be longer than 32 characters.");
            }

            uint?cidx = null;

            if (ctx.SpecIndex != null)
            {
                var ival = SSLVisitor.ParseIntegerLiteral(ctx.SpecIndex.Text, out var isus, out var perror);
                if (!ival.HasValue)
                {
                    vis.Error(ctx, "Could not parse integer literal.");
                }
                if (ival.Value < 0)
                {
                    vis.Error(ctx, "Specialization constant index cannot be less than 0.");
                }
                if (ival.Value > 255)
                {
                    vis.Error(ctx, "Specialization constant index cannot be greater than 255.");
                }
                cidx = (uint)ival.Value;
            }

            var type = ReflectionUtils.TranslateTypeContext(ctx.type());

            if (!type.HasValue)
            {
                vis.Error(ctx, $"Unable to convert constant '{name}' to internal type.");
            }
            if (type == ShaderType.Void)
            {
                vis.Error(ctx, $"The variable '{name}' cannot be of type 'void'.");
            }
            if (!type.Value.IsValueType())
            {
                vis.Error(ctx, "Globals constants must be a value type.");
            }

            return(new Variable(type.Value, name, VariableScope.Constant, true, null, cidx: cidx));
        }
        internal static Variable FromContext(SSLParser.UniformVariableContext ctx, SSLVisitor vis)
        {
            var name = ctx.Name.Text;

            if (name[0] == '$')
            {
                vis.Error(ctx, "Cannot start a variable with the character '$', this is reserved for built-in variables.");
            }
            if (name.Length > 32)
            {
                vis.Error(ctx, "Uniform names cannot be longer than 32 characters.");
            }

            var type = ReflectionUtils.TranslateTypeContext(ctx.type());

            if (!type.HasValue)
            {
                vis.Error(ctx, $"Unable to convert variable '{name}' to internal type.");
            }
            if (type == ShaderType.Void)
            {
                vis.Error(ctx, $"The variable '{name}' cannot be of type 'void'.");
            }

            ImageFormat?ifmt = null;
            uint?       si   = null;

            if (type.Value.IsImageType())
            {
                if (ctx.Qualifier?.imageLayoutQualifier() == null)
                {
                    vis.Error(ctx, "Storage image types must have a format qualifier.");
                }
                ifmt = ReflectionUtils.TranslateImageFormat(ctx.Qualifier.imageLayoutQualifier());
            }
            else if (type.Value.IsSubpassInput())
            {
                if (ctx.Qualifier?.INTEGER_LITERAL() == null)
                {
                    vis.Error(ctx, "Subpass inputs must have an index qualifier.");
                }
                var pv = SSLVisitor.ParseIntegerLiteral(ctx.Qualifier.INTEGER_LITERAL().GetText(), out var isus, out var error);
                if (!pv.HasValue)
                {
                    vis.Error(ctx, error);
                }
                if (pv.Value < 0)
                {
                    vis.Error(ctx, "Subpass input index cannot be less than 0.");
                }
                if (pv.Value > 255)
                {
                    vis.Error(ctx, "Subpass input index cannot be greater than 255.");
                }
                si = (uint)pv.Value;
            }
            else
            {
                if (ctx.Qualifier?.imageLayoutQualifier() != null || ctx.Qualifier?.INTEGER_LITERAL() != null)
                {
                    vis.Error(ctx, $"The handle type '{type}' cannot have qualifiers.");
                }
            }

            return(new Variable(type.Value, name, VariableScope.Uniform, false, null, ifmt: ifmt, si: si));
        }