public DekiScriptExpression Visit(DekiScriptAccess expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptExpression prefix = expr.Prefix.VisitWith(this, state);
            DekiScriptExpression index  = expr.Index.VisitWith(this, state);
            DekiScriptAccess     access = (DekiScriptAccess)DekiScriptExpression.Access(expr.Location, prefix, index);

            if ((prefix is DekiScriptLiteral) && (index is DekiScriptLiteral))
            {
                DekiScriptLiteral result = DekiScriptExpressionEvaluation.Instance.Evaluate(access, state, false);

                // check if result is a property
                if (DekiScriptRuntime.IsProperty(result))
                {
                    // retrieve property information
                    var descriptor = state.Runtime.ResolveRegisteredFunctionUri(((DekiScriptUri)result).Value);
                    if ((descriptor != null) && descriptor.IsIdempotent)
                    {
                        // evaluate property, since it never changes
                        return(state.Runtime.EvaluateProperty(expr.Location, result, state.Env));
                    }
                    return(DekiScriptExpression.Call(expr.Location, result, new DekiScriptList()));
                }
                return(result);
            }
            return(access);
        }
        public DekiScriptExpression Visit(DekiScriptAccess expr, DekiScriptOptimizerState state)
        {
            DekiScriptExpression prefix = expr.Prefix.VisitWith(this, state);
            DekiScriptExpression index  = expr.Index.VisitWith(this, state);
            DekiScriptAccess     access = new DekiScriptAccess(expr.Line, expr.Column, prefix, index);

            if ((prefix is DekiScriptLiteral) && (index is DekiScriptLiteral))
            {
                // BUGBUGBUG (steveb): don't eval properties!
                DekiScriptLiteral result = DekiScriptExpressionEvaluation.Instance.Evaluate(access, state.Env, false);

                // check if result is a property
                if (DekiScriptRuntime.IsProperty(result))
                {
                    // retrieve property information
                    DekiScriptFunction function;
                    if (DekiScriptLibrary.Functions.TryGetValue(((DekiScriptUri)result).Value, out function))
                    {
                        if (function is DekiScriptFunctionNative)
                        {
                            DekiScriptFunctionNative native = (DekiScriptFunctionNative)function;

                            // check if function is idempotent; if so, execute it
                            if (native.IsIdempotent)
                            {
                                // evaluate property, since it never changes
                                return(DekiScriptRuntime.EvaluateProperty(result, state.Env));
                            }
                        }
                    }
                    return(new DekiScriptCall(expr.Line, expr.Column, result, new DekiScriptList(), false));
                }
                return(result);
            }
            return(access);
        }
        internal DekiScriptLiteral Evaluate(DekiScriptAccess expr, DekiScriptExpressionEvaluationState state, bool evaluateProperties)
        {
            DekiScriptLiteral prefix = state.Pop(expr.Prefix.VisitWith(this, state));
            DekiScriptLiteral index  = state.Pop(expr.Index.VisitWith(this, state));

            switch (prefix.ScriptType)
            {
            case DekiScriptType.MAP: {
                DekiScriptLiteral result = ((DekiScriptMap)prefix)[index];
                if (evaluateProperties)
                {
                    result = state.Runtime.EvaluateProperty(expr.Location, result, state.Env);
                }
                return(result);
            }

            case DekiScriptType.LIST: {
                DekiScriptLiteral value  = DekiScriptExpression.Constant(index.AsNumber());
                DekiScriptLiteral result = ((DekiScriptList)prefix)[value];
                if (evaluateProperties)
                {
                    result = state.Runtime.EvaluateProperty(expr.Location, result, state.Env);
                }
                return(result);
            }

            case DekiScriptType.URI: {
                DekiScriptUri uri = (DekiScriptUri)prefix;

                // coerce the index type to STR
                index = DekiScriptExpression.Constant(index.AsString());
                if (index.ScriptType != DekiScriptType.STR)
                {
                    throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.STR });
                }

                // curry the argument
                DekiScriptList args;
                if (!uri.Arguments.IsNil)
                {
                    // the uri already has curried parameters, make sure they are in LIST format; otherwise fail
                    if (uri.Arguments.ScriptType != DekiScriptType.LIST)
                    {
                        throw new DekiScriptBadTypeException(expr.Location, uri.Arguments.ScriptType, new[] { DekiScriptType.NIL, DekiScriptType.LIST });
                    }
                    args = new DekiScriptList((DekiScriptList)uri.Arguments);
                }
                else
                {
                    args = new DekiScriptList();
                }
                args.Add(index);
                return(new DekiScriptUri(uri.Value, args));
            }

            case DekiScriptType.STR: {
                DekiScriptString text = (DekiScriptString)prefix;

                // coerce the index type to NUM
                double?value = index.AsNumber();
                if (value == null)
                {
                    throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.NUM });
                }

                // retrieve character at given index position
                int position = (int)value;
                if ((position < 0) || (position >= text.Value.Length))
                {
                    // index is out of bounds, return nil
                    return(DekiScriptNil.Value);
                }
                return(DekiScriptExpression.Constant(text.Value[position].ToString()));
            }

            case DekiScriptType.XML: {
                string path = index.AsString();
                if (path == null)
                {
                    throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.STR });
                }
                XDoc doc = ((DekiScriptXml)prefix).Value[path];
                if (doc.HasName("html"))
                {
                    doc = DekiScriptLibrary.CleanseHtmlDocument(doc);
                }
                return(new DekiScriptXml(doc));
            }

            case DekiScriptType.NIL:
                return(DekiScriptNil.Value);
            }
            throw new DekiScriptBadTypeException(expr.Location, prefix.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST, DekiScriptType.XML, DekiScriptType.STR, DekiScriptType.URI });
        }
 public DekiScriptOutputBuffer.Range Visit(DekiScriptAccess expr, DekiScriptExpressionEvaluationState state)
 {
     return(state.Push(Evaluate(expr, state, true)));
 }
 public DekiScriptLiteral Visit(DekiScriptAccess expr, DekiScriptEnv env)
 {
     return(Evaluate(expr, env, true));
 }