private Expr Unary()
        {
            if (Match(TokenType.NOT, TokenType.MINUS))
            {
                Token op    = Previous;
                Expr  right = Cast();

                if (right is Expr.Literal lit)
                {
                    var type = new TypeSpecifier {
                        Type = lit.Type, Dimensions = 0
                    };

                    if (op.Type == TokenType.NOT)
                    {
                        if (type.IsBool())
                        {
                            bool value = (bool)lit.Value;

                            return(new Expr.Literal(lit.Type, !value));
                        }
                        else
                        {
                            throw Error("Trying to invert a non-boolean value");
                        }
                    }
                    else
                    {
                        if (type.IsInt())
                        {
                            long value = (long)lit.Value;

                            return(new Expr.Literal(lit.Type, -value));
                        }
                        else if (type.IsFloat())
                        {
                            double value = (double)lit.Value;

                            return(new Expr.Literal(lit.Type, -value));
                        }
                        else
                        {
                            throw Error("Trying to negate a non-numeric value");
                        }
                    }
                }

                return(new Expr.Unary(op, right));
            }

            return(Invoke());
        }
        private Expr Relational()
        {
            var expr = Additive();

            while (Match(TokenType.GREATER, TokenType.GREATER_EQUAL, TokenType.LESS, TokenType.LESS_EQUAL))
            {
                Token op    = Previous;
                Expr  right = Additive();

                if (expr is Expr.Literal l && right is Expr.Literal r)
                {
                    var typel = new TypeSpecifier {
                        Type = l.Type, Dimensions = 0
                    };
                    var typer = new TypeSpecifier {
                        Type = r.Type, Dimensions = 0
                    };

                    if (typer.ImplicitCastableTo(typel))
                    {
                        if (typel.Type == TypeEnum.BOOL)
                        {
                            throw Error($"Boolean values are not comparable with '{op.Type}'");
                        }

                        if (typel.IsInt())
                        {
                            return(CompareLiterals <long>(op.Type, l.Value, r.Value));
                        }
                        else if (typel.IsFloat())
                        {
                            return(CompareLiterals <double>(op.Type, l.Value, r.Value));
                        }
                        else
                        {
                            throw Error("Something wrong with literal comparison");
                        }
                    }
                    else
                    {
                        throw Error($"'{typer}' not implicitly castable to '{typel}'");
                    }
                }

                expr = new Expr.Binary(expr, op, right);
            }

            return(expr);
        }
        private Expr Multiplicative()
        {
            var expr = Cast();

            while (Match(TokenType.DIV, TokenType.MULT))
            {
                Token op    = Previous;
                Expr  right = Cast();

                if (expr is Expr.Literal l && right is Expr.Literal r)
                {
                    var typel = new TypeSpecifier {
                        Type = l.Type, Dimensions = 0
                    };
                    var typer = new TypeSpecifier {
                        Type = r.Type, Dimensions = 0
                    };

                    if (typer.ImplicitCastableTo(typel))
                    {
                        if (typel.IsInt())
                        {
                            long one = (long)l.Value;
                            long two = (long)r.Value;

                            if (op.Type == TokenType.DIV)
                            {
                                return(new Expr.Literal(typel.Type, one / two));
                            }
                            else
                            {
                                return(new Expr.Literal(typel.Type, one * two));
                            }
                        }
                        else if (typel.IsFloat())
                        {
                            double one = (double)l.Value;
                            double two = (double)r.Value;

                            if (op.Type == TokenType.DIV)
                            {
                                return(new Expr.Literal(typel.Type, one / two));
                            }
                            else
                            {
                                return(new Expr.Literal(typel.Type, one * two));
                            }
                        }
                        else
                        {
                            throw Error("Something wrong on Multiplicative");
                        }
                    }
                    else
                    {
                        throw Error($"'{typer}' not implicitly castable to '{typel}'");
                    }
                }

                expr = new Expr.Binary(expr, op, right);
            }

            return(expr);
        }