Exemple #1
0
        private DekiScriptLiteral InvokeHelper(DekiScriptRuntime runtime, DekiScriptList args)
        {
            // convert passed in arguments
            object[] arguments = new object[Parameters.Length];
            int      i         = 0;

            try {
                for (; i < Parameters.Length; ++i)
                {
                    var value = args[i].NativeValue;

                    // check if we need to convert the value
                    if ((value != null) && (Parameters[i].NativeType != typeof(object)))
                    {
                        // check for the special case where we cast from XML to STR
                        if ((value is XDoc) && (Parameters[i].NativeType == typeof(string)))
                        {
                            XDoc xml = (XDoc)value;
                            if (xml.HasName("html"))
                            {
                                value = xml["body[not(@target)]"].Contents;
                            }
                            else
                            {
                                value = xml.ToString();
                            }
                        }
                        else
                        {
                            // rely on the default type conversion rules
                            value = SysUtil.ChangeType(value, Parameters[i].NativeType);
                        }
                    }
                    arguments[i] = value;
                }
            } catch {
                throw new ArgumentException(string.Format("could not convert parameter '{0}' (index {1}) from {2} to {3}", Parameters[i].Name, i, args[i].ScriptTypeName, DekiScriptLiteral.AsScriptTypeName(Parameters[i].ScriptType)));
            }

            // invoke method
            var result = _invoke(runtime, arguments);

            // check if result is a URI
            if (result is XUri)
            {
                // normalize URI if possible
                DreamContext context = DreamContext.CurrentOrNull;
                if (context != null)
                {
                    result = context.AsPublicUri((XUri)result);
                }
            }
            var literal = DekiScriptLiteral.FromNativeValue(result);

            try {
                return(literal.Convert(ReturnType));
            } catch (DekiScriptInvalidCastException) {
                throw new DekiScriptInvalidReturnCastException(Location.None, literal.ScriptType, ReturnType);
            }
        }
Exemple #2
0
        public static Hashtable ListGroupBy(
            [DekiScriptParam("list value")] ArrayList list,
            [DekiScriptParam("expression to apply for grouping (use '$' to refer to the current item)")] string expression,
            DekiScriptRuntime runtime
            )
        {
            Hashtable            result = new Hashtable(StringComparer.OrdinalIgnoreCase);
            DekiScriptExpression expr   = DekiScriptParser.Parse(new Location("list.groupby(expression)"), expression);

            // loop over all items in list
            foreach (object entry in list)
            {
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, DekiScriptLiteral.FromNativeValue(entry));

                // evalute grouping expression
                string key = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env).AsString();
                if (key != null)
                {
                    // check if an accumulation list already exists; otherwise, create one
                    ArrayList accumulator = (ArrayList)result[key];
                    if (accumulator == null)
                    {
                        accumulator = new ArrayList();
                        result[key] = accumulator;
                    }
                    accumulator.Add(entry);
                }
            }
            return(result);
        }
Exemple #3
0
        public static Hashtable MapFilter(
            [DekiScriptParam("map value")] Hashtable map,
            [DekiScriptParam("condition to execute for each item (use '$' to refer to the key-value pair)")] string condition,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr   = DekiScriptParser.Parse(new Location("map.select(condition)"), condition);
            Hashtable            result = new Hashtable(StringComparer.OrdinalIgnoreCase);

            foreach (DictionaryEntry entry in map)
            {
                DekiScriptMap keyvalue = new DekiScriptMap();
                object        value    = Eval(entry.Value, runtime);
                keyvalue.Add("key", DekiScriptLiteral.FromNativeValue(entry.Key));
                keyvalue.Add("value", DekiScriptLiteral.FromNativeValue(value));
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, keyvalue);
                DekiScriptLiteral test = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env);
                if (!test.IsNilFalseZero)
                {
                    result.Add(entry.Key, value);
                }
            }
            return(result);
        }
Exemple #4
0
            //--- Methods ---
            public int Compare(object left, object right)
            {
                _values.Add("left", DekiScriptLiteral.FromNativeValue(left));
                _values.Add("right", DekiScriptLiteral.FromNativeValue(right));
                _env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, _values);
                DekiScriptLiteral test = _runtime.Evaluate(_compare, DekiScriptEvalMode.EvaluateSafeMode, _env);

                return((int)(test.AsNumber() ?? 0.0));
            }
Exemple #5
0
        public static ArrayList ListApply(
            [DekiScriptParam("list value")] ArrayList list,
            [DekiScriptParam("expression to apply (use '$' to refer to the current item)")] string expression,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr   = DekiScriptParser.Parse(new Location("list.apply(expression)"), expression);
            ArrayList            result = new ArrayList();

            foreach (object entry in list)
            {
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, DekiScriptLiteral.FromNativeValue(entry));
                result.Add(runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env).NativeValue);
            }
            return(result);
        }
Exemple #6
0
        public static ArrayList ListIntersect(
            [DekiScriptParam("first list")] ArrayList first,
            [DekiScriptParam("second list")] ArrayList second,
            [DekiScriptParam("expression to determine if item from the first list should be included in final list (return true to include, false to exclude; use '$left' and '$right' to refer to the current item from the first and seconds lists respectively; default: equality condition)", true)] string condition,
            DekiScriptRuntime runtime
            )
        {
            ArrayList result = new ArrayList();

            if (condition != null)
            {
                // loop over both lists and keep items from the first list based on the outcome of the condition
                DekiScriptExpression expr = DekiScriptParser.Parse(new Location("list.intersect(condition)"), condition);
                foreach (object left in first)
                {
                    foreach (object right in second)
                    {
                        DekiScriptEnv env      = runtime.CreateEnv();
                        DekiScriptMap keyvalue = new DekiScriptMap();
                        keyvalue.Add("left", DekiScriptLiteral.FromNativeValue(left));
                        keyvalue.Add("right", DekiScriptLiteral.FromNativeValue(right));
                        env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, keyvalue);
                        DekiScriptLiteral test = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env);
                        if (!test.IsNilFalseZero)
                        {
                            result.Add(left);
                            break;
                        }
                    }
                }
            }
            else
            {
                // using simple containment check to keep items
                foreach (object item in first)
                {
                    if (second.Contains(item))
                    {
                        result.Add(item);
                    }
                }
            }
            return(result);
        }
Exemple #7
0
        public static Hashtable MapApply(
            [DekiScriptParam("map value")] Hashtable map,
            [DekiScriptParam("expression to apply (use '$' to refer to the item)")] string expression,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr   = DekiScriptParser.Parse(new Location("map.apply(expression)"), expression);
            Hashtable            result = new Hashtable(StringComparer.OrdinalIgnoreCase);

            foreach (DictionaryEntry entry in map)
            {
                DekiScriptMap keyvalue = new DekiScriptMap();
                keyvalue.Add("key", DekiScriptLiteral.FromNativeValue(entry.Key));
                keyvalue.Add("value", DekiScriptLiteral.FromNativeValue(Eval(entry.Value, runtime)));
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, keyvalue);
                result.Add(entry.Key, runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env));
            }
            return(result);
        }
Exemple #8
0
        public static object ListReduce(
            [DekiScriptParam("list value")] ArrayList list,
            [DekiScriptParam("expression to compute combined value (use '$value' and '$item' to refer to the current value and item, respectively)")] string expression,
            [DekiScriptParam("starting value (default: nil)", true)] object value,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr = DekiScriptParser.Parse(new Location("list.reduce(expression)"), expression);

            foreach (object entry in list)
            {
                DekiScriptEnv env    = runtime.CreateEnv();
                DekiScriptMap values = new DekiScriptMap();
                values.Add("value", DekiScriptLiteral.FromNativeValue(value));
                values.Add("item", DekiScriptLiteral.FromNativeValue(entry));
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, values);
                value = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env).NativeValue;
            }
            return(value);
        }
        public static XDoc WebLink(
            [DekiScriptParam("link uri")] string uri,
            [DekiScriptParam("link contents; can be text, an image, or another document (default: link uri)", true)] object text,
            [DekiScriptParam("link hover title (default: none)", true)] string title,
            [DekiScriptParam("link target (default: none)", true)] string target
            )
        {
            // check __settings.nofollow if links should be followed or not
            bool         nofollow = true;
            DreamContext context  = DreamContext.CurrentOrNull;

            if (context != null)
            {
                DekiScriptEnv env = context.GetState <DekiScriptEnv>();
                if (env != null)
                {
                    // TODO (steveb): this should be stored in the runtime instead!
                    DekiScriptBool setting = env.Vars.GetAt(new[] { DekiScriptEnv.SETTINGS, "nofollow" }) as DekiScriptBool;
                    if (setting != null)
                    {
                        nofollow = setting.AsBool() ?? true;
                    }
                }
            }

            XDoc result = DekiScriptLiteral.FromNativeValue(text ?? uri).AsEmbeddableXml(true);
            XDoc body   = result["body[not(@target)]"];

            result.Start("body").Start("a");
            if (nofollow)
            {
                result.Attr("rel", "custom nofollow");
            }
            else
            {
                result.Attr("rel", "custom");
            }
            result.Attr("href", WebCheckUri(uri)).Attr("title", title).Attr("target", target).AddNodes(body).End().End();
            body.Remove();
            return(result);
        }
Exemple #10
0
        public static int ListCount(
            [DekiScriptParam("list value")] ArrayList list,
            [DekiScriptParam("condition to execute for each item (use '$' to refer to the item)")] string condition,
            DekiScriptRuntime runtime
            )
        {
            DekiScriptExpression expr = DekiScriptParser.Parse(new Location("list.count(condition)"), condition);
            int count = 0;

            foreach (object entry in list)
            {
                DekiScriptEnv env = runtime.CreateEnv();
                env.Vars.Add(DekiScriptRuntime.DEFAULT_ID, DekiScriptLiteral.FromNativeValue(entry));
                DekiScriptLiteral test = runtime.Evaluate(expr, DekiScriptEvalMode.EvaluateSafeMode, env);
                if (!test.IsNilFalseZero)
                {
                    ++count;
                }
            }
            return(count);
        }
 public static string StringSerialize(
     [DekiScriptParam("value", true)] object value
     )
 {
     return(DekiScriptLiteral.FromNativeValue(value).ToString());
 }
        public object Store(
            [DekiExtParam("document id")] string id,
            [DekiExtParam("document to cache", true)] object document,
            [DekiExtParam("caching duration in seconds (range: 300+; default: 300)", true)] double?ttl
            )
        {
            if (document == null)
            {
                return(Clear(id));
            }

            // fetch entry from cache
            CacheEntry result;
            bool       isNew = true;

            lock (_cacheLookup) {
                _cacheLookup.TryGetValue(id, out result);
            }

            // check if we have a cached entry
            if (result != null)
            {
                _log.DebugFormat("cache hit for '{0}'", result.Id);
                isNew = false;
                result.ResetMemoryExpiration();
            }
            else
            {
                _log.DebugFormat("new cache item for '{0}'", id);
                result = new CacheEntry(id, ttl);
            }

            // update cache with document
            DekiScriptLiteral literal = DekiScriptLiteral.FromNativeValue(document);
            XDoc xml = new DekiScriptList().Add(literal).ToXml();

            result.Cache = xml.ToString();

            // start timer to clean-up cached result
            if (result.Cache != null)
            {
                XDoc infoDoc = new XDoc("cache-entry")
                               .Elem("guid", result.Guid)
                               .Elem("id", result.Id)
                               .Elem("expires", result.Expires);
                lock (result) {
                    Storage.At(CACHE_DATA, result.Guid + ".bin").PutAsync(new DreamMessage(DreamStatus.Ok, null, MimeType.BINARY, Encoding.UTF8.GetBytes(result.Cache))).Wait();
                    Storage.At(CACHE_INFO, result.Guid + ".xml").PutAsync(infoDoc).Wait();
                }
                if (isNew)
                {
                    lock (_cacheLookup) {
                        _cacheLookup[id] = result;
                    }

                    // this timer removes the cache entry from disk
                    SetupCacheTimer(result);
                }
            }
            return(document);
        }
        public DekiScriptOutputBuffer.Range Visit(DekiScriptBinary expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptExpression Left  = expr.Left;
            DekiScriptExpression Right = expr.Right;

            switch (expr.OpCode)
            {
            case DekiScriptBinary.Op.LeftValue:
                return(Left.VisitWith(this, state));

            case DekiScriptBinary.Op.IdentityEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.IdentityEqual(left, right)));
            }

            case DekiScriptBinary.Op.IdentityNotEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.IdentityNotEqual(left, right)));
            }

            case DekiScriptBinary.Op.IsType: {
                DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state));
                string            type = ((DekiScriptString)Right).Value;
                return(state.Push(DekiScriptExpression.Constant(type.EqualsInvariantIgnoreCase("any") || left.ScriptTypeName.EqualsInvariantIgnoreCase(type))));
            }

            case DekiScriptBinary.Op.Equal: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.Equal(left, right)));
            }

            case DekiScriptBinary.Op.NotEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.NotEqual(left, right)));
            }

            case DekiScriptBinary.Op.GreaterOrEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() >= right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) >= 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.GreaterThan: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() > right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) > 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.LessOrEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() <= right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) <= 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.LessThan: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() < right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) < 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.LogicalAnd: {
                DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state));
                if (!result.IsNilFalseZero)
                {
                    return(Right.VisitWith(this, state));
                }
                return(state.Push(result));
            }

            case DekiScriptBinary.Op.LogicalOr: {
                DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state));
                if (result.IsNilFalseZero)
                {
                    return(Right.VisitWith(this, state));
                }
                return(state.Push(result));
            }

            case DekiScriptBinary.Op.Addition:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() + state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.Division:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() / state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.Modulo: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if ((left is DekiScriptString) && ((right is DekiScriptMap) || (right is DekiScriptList)))
                {
                    // NOTE (steveb): string.format shorthand notation: "abc = $abc" % { abc: 123 } -OR- "0 = $0" % [ 123 ]
                    return(state.Push(DekiScriptLiteral.FromNativeValue(DekiScriptLibrary.StringFormat(((DekiScriptString)left).Value, right.NativeValue))));
                }
                else
                {
                    return(state.Push(DekiScriptExpression.Constant(left.AsNumber() % right.AsNumber())));
                }
            }

            case DekiScriptBinary.Op.Multiplication:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() * state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.Subtraction:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() - state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.NullCoalesce: {
                DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state));
                if (result.IsNil)
                {
                    return(Right.VisitWith(this, state));
                }
                return(state.Push(result));
            }

            case DekiScriptBinary.Op.Concat: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (left is DekiScriptNil)
                {
                    return(state.Push(right));
                }
                else if (right is DekiScriptNil)
                {
                    return(state.Push(left));
                }
                else if ((left is DekiScriptMap) && (right is DekiScriptMap))
                {
                    // left and right expressions are maps, merge them
                    DekiScriptMap result = new DekiScriptMap();
                    result.AddRange((DekiScriptMap)left);
                    result.AddRange((DekiScriptMap)right);
                    return(state.Push(result));
                }
                else if ((left is DekiScriptList) && (right is DekiScriptList))
                {
                    // left and right expressions are lists, concatenate them
                    DekiScriptList result = new DekiScriptList();
                    result.AddRange((DekiScriptList)left);
                    result.AddRange((DekiScriptList)right);
                    return(state.Push(result));
                }
                else
                {
                    // treat left and right expressions as strings
                    string leftText  = left.AsString();
                    string rightText = right.AsString();
                    if ((leftText != null) && (rightText != null))
                    {
                        return(state.Push(DekiScriptExpression.Constant(leftText + rightText)));
                    }
                    else if (leftText != null)
                    {
                        return(state.Push(DekiScriptExpression.Constant(leftText)));
                    }
                    else if (rightText != null)
                    {
                        return(state.Push(DekiScriptExpression.Constant(rightText)));
                    }
                    else
                    {
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
            }

            case DekiScriptBinary.Op.UriAppend: {
                // TODO (steveb): we should throw an exception when the LHS is not a valid string or uri

                XUri   left   = XUri.TryParse(state.Pop(Left.VisitWith(this, state)).AsString());
                string result = null;
                if (left != null)
                {
                    DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                    if (right is DekiScriptString)
                    {
                        result = DekiScriptLibrary.UriBuild(left, right.AsString(), null);
                    }
                    else if (right is DekiScriptMap)
                    {
                        result = DekiScriptLibrary.UriBuild(left, null, (Hashtable)right.NativeValue);
                    }
                    else
                    {
                        result = left.ToString();
                    }
                }
                return(state.Push(DekiScriptLiteral.FromNativeValue(result)));
            }

            case DekiScriptBinary.Op.InCollection: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (right is DekiScriptList)
                {
                    foreach (DekiScriptLiteral item in ((DekiScriptList)right).Value)
                    {
                        if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero)
                        {
                            return(state.Push(DekiScriptBool.True));
                        }
                    }
                    return(state.Push(DekiScriptBool.False));
                }
                else if (right is DekiScriptMap)
                {
                    foreach (DekiScriptLiteral item in ((DekiScriptMap)right).Value.Values)
                    {
                        if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero)
                        {
                            return(state.Push(DekiScriptBool.True));
                        }
                    }
                    return(state.Push(DekiScriptBool.False));
                }
                else
                {
                    return(state.Push(DekiScriptBool.False));
                }
            }
            }
            throw new InvalidOperationException("invalid op code:" + expr.OpCode);
        }