protected override Expression VisitBinary(BinaryExpression node)
        {
            switch (node.NodeType)
            {
            case ExpressionType.ArrayIndex:
                Visit(node.Left);
                GlslVariable variable = _bufferVariables.Pop();
                _shader.Main.Append(variable.Name);
                _shader.Main.Append("[");
                Visit(node.Right);
                _shader.Main.Append("]");
                break;

            case ExpressionType.Multiply:
                Visit(node.Right);
                _shader.Main.Append($" {node.NodeType.GlslSymbol()} ");
                Visit(node.Left);
                break;

            default:
                Visit(node.Left);
                _shader.Main.Append($" {node.NodeType.GlslSymbol()} ");
                Visit(node.Right);
                break;
            }
            return(node);
        }
        protected override Expression VisitParameter(ParameterExpression node)
        {
            EnsureTypeAdded(node.Type);

            GlslVariable variable = _lambdaParamToBufferMap[node.Name];
            string       srcName  = variable.Name;

            while (_parameterMemberChain.Count > 0)
            {
                MemberInfo member = _parameterMemberChain.Pop();
                srcName += "." + member.GlslName();
            }

            _shader.Main.Append(srcName);

            return(node);
        }
        public VulkanComputeContext Translate(Expression expression, VulkanDevice device)
        {
            _device = device;
            _shader = new GlslComputeShader();

            _ctx = new VulkanComputeContext(device);

            Visit(expression);

            _ctx.Output = ResolveOutput(_ctx.Inputs[0].Count, expression);
            GlslVariable outputVar = _shader.AddBuffer(_ctx.Output.ElementType, false, true);

            _shader.Main.AppendLine($"{outputVar.Name} = {SrcVariable.Name};");

            _ctx.SpirV = _shader.CompileToSpirV();

            return(_ctx);
        }
        private bool HandleQueryMethodCall(MethodCallExpression node)
        {
            if (node.Method.DeclaringType != typeof(Queryable))
            {
                return(false);
            }

            switch (node.Method.Name)
            {
            case nameof(Queryable.Select):     // Implements LINQ Select query operator.
            {
                Visit(node.Arguments[0]);

                DstVariable = GlslVariable.Next(node.Type.GenericTypeArguments[0]);

                _shader.Main.Append($"{DstVariable.Type.GlslName()} {DstVariable.Name} = ");

                _parameterMemberChain.Clear();
                _lambdaParamToBufferMap.Clear();
                var lambda = (LambdaExpression)node.Arguments[1].StripQuotes();
                _lambdaParamToBufferMap.Add(lambda.Parameters[0].Name, _bufferVariables.Pop());
                _isBufferStartOfChain = false;

                Visit(lambda.Body);

                if (!_shader.Main.IsNewline)
                {
                    _shader.Main.AppendLine(";");
                }

                _bufferVariables.Push(DstVariable);
                SrcVariable = DstVariable;
                return(true);
            }

            case nameof(Queryable.Zip):     // Implements LINQ Zip query operator.
            {
                Visit(node.Arguments[0]);
                Visit(node.Arguments[1]);

                DstVariable = GlslVariable.Next(node.Type.GenericTypeArguments[0]);

                _shader.Main.Append($"{DstVariable.Type.GlslName()} {DstVariable.Name} = ");

                _parameterMemberChain.Clear();
                _lambdaParamToBufferMap.Clear();
                var lambda = (LambdaExpression)node.Arguments[2].StripQuotes();
                _lambdaParamToBufferMap.Add(lambda.Parameters[1].Name, _bufferVariables.Pop());
                _lambdaParamToBufferMap.Add(lambda.Parameters[0].Name, _bufferVariables.Pop());
                _isBufferStartOfChain = false;

                Visit(lambda.Body);

                if (!_shader.Main.IsNewline)
                {
                    _shader.Main.AppendLine(";");
                }

                _bufferVariables.Push(DstVariable);
                SrcVariable = DstVariable;
                return(true);
            }

            default:
            {
                return(false);
            }
            }
        }