public DekiScriptExpression Visit(DekiScriptUnary expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptExpression value  = expr.Value.VisitWith(this, state);
            DekiScriptExpression result = DekiScriptExpression.UnaryOp(expr.Location, expr.OpCode, value);

            if (value is DekiScriptLiteral)
            {
                return(state.Pop(result.VisitWith(DekiScriptExpressionEvaluation.Instance, state)));
            }
            return(result);
        }
        public DekiScriptExpression Visit(DekiScriptUnary expr, DekiScriptOptimizerState state)
        {
            DekiScriptExpression value  = expr.Value.VisitWith(this, state);
            DekiScriptExpression result = new DekiScriptUnary(expr.Line, expr.Column, expr.OpCode, value);

            if (value is DekiScriptLiteral)
            {
                return(result.Evaluate(state.Env));
            }
            return(result);
        }
        public DekiScriptOutputBuffer.Range Visit(DekiScriptUnary expr, DekiScriptExpressionEvaluationState state)
        {
            switch (expr.OpCode)
            {
            case DekiScriptUnary.Op.Negate:
                return(state.Push(DekiScriptExpression.Constant(-state.Pop(expr.Value.VisitWith(this, state)).AsNumber())));

            case DekiScriptUnary.Op.LogicalNot:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(expr.Value.VisitWith(this, state)).IsNilFalseZero)));

            case DekiScriptUnary.Op.TypeOf:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(expr.Value.VisitWith(this, state)).ScriptTypeName)));

            case DekiScriptUnary.Op.Length: {
                DekiScriptLiteral value = state.Pop(expr.Value.VisitWith(this, state));
                switch (value.ScriptType)
                {
                case DekiScriptType.NIL:
                    return(state.Push(DekiScriptExpression.Constant(0)));

                case DekiScriptType.LIST:
                    return(state.Push(DekiScriptExpression.Constant(((DekiScriptList)value).Value.Count)));

                case DekiScriptType.STR:
                    return(state.Push(DekiScriptExpression.Constant(((DekiScriptString)value).Value.Length)));

                case DekiScriptType.MAP:
                    return(state.Push(DekiScriptExpression.Constant(((DekiScriptMap)value).Value.Count)));

                case DekiScriptType.XML:
                    return(state.Push(DekiScriptExpression.Constant(((DekiScriptXml)value).Value.ListLength)));

                default:
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }
            }
            throw new InvalidOperationException("invalid op code:" + expr.OpCode);
        }
        public DekiScriptLiteral Visit(DekiScriptUnary expr, DekiScriptEnv env)
        {
            switch (expr.OpCode)
            {
            case DekiScriptUnary.Op.Negate:
                return(DekiScriptNumber.New(-expr.Value.VisitWith(this, env).AsNumber()));

            case DekiScriptUnary.Op.LogicalNot:
                return(DekiScriptBool.New(expr.Value.VisitWith(this, env).IsNilFalseZero));

            case DekiScriptUnary.Op.TypeOf:
                return(DekiScriptString.New(expr.Value.VisitWith(this, env).ScriptTypeName));

            case DekiScriptUnary.Op.Length: {
                DekiScriptLiteral value = expr.Value.VisitWith(this, env);
                switch (value.ScriptType)
                {
                case DekiScriptType.NIL:
                    return(DekiScriptNumber.New(0));

                case DekiScriptType.LIST:
                    return(DekiScriptNumber.New(((DekiScriptList)value).Value.Count));

                case DekiScriptType.STR:
                    return(DekiScriptNumber.New(((DekiScriptString)value).Value.Length));

                case DekiScriptType.MAP:
                    return(DekiScriptNumber.New(((DekiScriptMap)value).Value.Count));

                case DekiScriptType.XML:
                    return(DekiScriptNumber.New(((DekiScriptXml)value).Value.ListLength));

                default:
                    return(DekiScriptNil.Value);
                }
            }
            }
            throw new InvalidOperationException("invalid op code:" + expr.OpCode);
        }