internal static Variable FromContext(SSLParser.VariableDeclarationContext ctx, SSLVisitor vis, VariableScope scope)
        {
            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.");
            }

            if (ctx.KW_FLAT() != null && scope != VariableScope.Internal)
            {
                vis.Error(ctx, "'flat' qualifier is only valid for internals.");
            }

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

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

            uint?asize = null;

            if (ctx.arrayIndexer() != null)
            {
                if (!vis.TryParseArrayIndexer(ctx.arrayIndexer(), (null, null), out var aidx, out var error))
                {
                    vis.Error(ctx.arrayIndexer(), error);
                }
                if (aidx.Index2 != null)
                {
                    vis.Error(ctx.arrayIndexer(), "Cannot declare multi-dimensional arrays.");
                }
                if (!aidx.Index1.GetIntegerLiteral().HasValue)                 // Must be a literal (OR A SPEC CONSTANT TODO)
                {
                    vis.Error(ctx.arrayIndexer(), "Must use integer literals when declaring arrays.");
                }
                asize = (uint)aidx.Index1.GetIntegerLiteral().Value;
                if (asize.Value > 255)
                {
                    vis.Error(ctx.arrayIndexer(), "Cannot declare arrays larger than 255.");
                }
            }

            return(new Variable(type.Value, name, scope, false, asize, flat: (ctx.KW_FLAT() != null)));
        }
        // Creates an expression result by applying array indexers and swizzles, if present
        public static ExprResult ApplyModifiers(SSLVisitor vis, ExprResult res, SSLParser.ArrayIndexerContext actx, ITerminalNode swizzle)
        {
            bool hasa = (actx != null);
            bool hass = (swizzle != null);

            // This prevents duplication in the event that there is an ssa already, and there is no array indexer or swizzle
            if (res.HasSSA)
            {
                res = new ExprResult(res.Type, null, res.SSA.Name);
            }

            if (hasa)
            {
                var lim =
                    res.IsArray ? res.ArraySize : res.Type.IsVectorType() ? res.Type.GetComponentCount() :
                    ((res.Type == ShaderType.Mat2) ? 2u : (res.Type == ShaderType.Mat3) ? 3u : 4u);
                if (!vis.TryParseArrayIndexer(actx, (lim - 1, res.Type.IsMatrixType() ? lim - 1 : (uint?)null), out var aidx, out var error))
                {
                    vis.Error(actx, error);
                }
                if (res.IsArray)
                {
                    if (aidx.Index2 != null)
                    {
                        vis.Error(actx, "Multi-dimensional arrays are not supported.");
                    }
                    res = new ExprResult(res.Type, null, $"{res.RefText}[{aidx.Index1.RefText}]");
                }
                else if (res.Type.IsVectorType())
                {
                    if (aidx.Index2 != null)
                    {
                        vis.Error(actx, "Vectors cannot have more than one array indexer.");
                    }
                    res = new ExprResult(res.Type.GetComponentType(), null, $"{res.RefText}[{aidx.Index1.RefText}]");
                }
                else if (res.Type.IsMatrixType())
                {
                    if (aidx.Index2 == null)
                    {
                        vis.Error(actx, "Matrices must have two array indexers to access their members.");
                    }
                    res = new ExprResult(ShaderType.Float, null, $"{res.RefText}[{aidx.Index1.RefText}][{aidx.Index2.RefText}]");
                }
                else
                {
                    vis.Error(actx, "The preceeding expression cannot have array indexers applied to it.");
                }
            }

            if (hass)
            {
                if (!res.Type.IsVectorType())
                {
                    vis.Error(swizzle.Symbol, "Cannot apply a swizzle to a non-vector type.");
                }
                var stxt = swizzle.Symbol.Text.Substring(1);
                if (stxt.Length > 4)
                {
                    vis.Error(swizzle.Symbol, "A swizzle cannot have more than four components.");
                }
                foreach (var swc in stxt)
                {
                    if (!ReflectionUtils.IsSwizzleValid(res.Type, swc))
                    {
                        vis.Error(swizzle.Symbol, $"The swizzle character '{swc}' is not valid for this type.");
                    }
                }
                res = new ExprResult(res.Type.ToVectorType((uint)stxt.Length).Value, null, $"{res.RefText}.{stxt}");
            }

            return(res);
        }