예제 #1
0
 public static object Return(VarCtx varCtx, object value)
 {
     varCtx.Func.ReturnValue = value;
     varCtx.Func.Returned    = true;
     varCtx.Break            = VarCtx.BreakMode.Return;
     return(value);
 }
예제 #2
0
        VarCtx EnterInterpreter(FuncCtx entry, object[] args)
        {
            var resultHolder = new VarCtx(null, null, null, this);

            try
            {
                Result = Block.CallFunc(resultHolder, entry, args);
            }
            catch (Exception e)
            {
                resultHolder.Break           = VarCtx.BreakMode.Throw;
                resultHolder.ScriptException = new RuntimeException(e.Message, resultHolder);
            }
            if (resultHolder.Break == VarCtx.BreakMode.Throw)
            {
                if (OnException == null)
                {
                    SyncDebug("Unhandleded exception: " + resultHolder.ScriptException);
                }
                else
                {
                    SyncCtx.Send((d) => OnException(-1, resultHolder.ScriptException), null);
                }
            }
            return(resultHolder);
        }
예제 #3
0
        private object UnaryArifm(VarCtx ctx, object a)
        {
            Type maxType = null;
            Type aType   = a == null ? typeof(DumbNullType) : a.GetType();

            foreach (var kp in Ops)
            {
                if (kp.Key.IsAssignableFrom(aType))
                {
                    maxType = kp.Key;
                    break;
                }
            }
            ;
            if (maxType == null)
            {
                throw new Exception("Can't cast type for " + aType);
            }
            if (maxType.IsInterface)
            {
                return(Ops[maxType](a, null));
            }

            //var ao = a == null ? null : Convert.ChangeType(a, maxType);
            return(Ops[maxType](a, null));
        }
예제 #4
0
        public static object DeclareFunc(VarCtx curCtx, Function func)
        {
            var funcCtx = new FuncCtx {
                ParentScope = curCtx, FunctionProto = func
            };

            return(funcCtx);
        }
예제 #5
0
 FuncCtx CreateFunc(VarCtx scope, string name, Func <VarCtx, object[], object> func)
 {
     return(CreateFunc(scope, name, new Function
     {
         ArgNames = new string[] { },
         Native = func
     }));
 }
예제 #6
0
 public VarCtx(VarCtx parentOnStack, VarCtx parScope, Block block, Interpreter interp)
 {
     CurBlock      = block;
     ParentOnStack = parentOnStack;
     ParentScope   = parScope;
     Func          = parScope?.Func;
     Interp        = interp;
 }
예제 #7
0
 FuncCtx CreateSynchronizedFunc(VarCtx scope, string name, Func <VarCtx, object[], object> func)
 {
     return(CreateFunc(scope, name, (c, d) =>
     {
         object result = null;
         SyncCtx.Send((state) => result = func(c, d), null);
         return result;
     }));;
 }
예제 #8
0
        public static object NewList(VarCtx curCtx, object length)
        {
            var len = GetArrayKey(length);

            if (len >= 0)
            {
                return(new object[len].ToList());
            }
            return(Throw(curCtx, "Invalid array length " + length));
        }
예제 #9
0
        FuncCtx CreateFunc(VarCtx scope, string name, Function func)
        {
            func.Name = name;
            var result = new FuncCtx
            {
                FunctionProto = func,
                ParentScope   = scope
            };

            return(result);
        }
예제 #10
0
        public object Arifm(VarCtx ctx, object a, object b)
        {
            try
            {
                if (Unary)
                {
                    return(UnaryArifm(ctx, a));
                }

                Type aType   = a == null ? typeof(DumbNullType) : a.GetType();
                Type bType   = b == null ? typeof(DumbNullType) : b.GetType();
                Type maxType = null;
                foreach (var kp in Ops)
                {
                    //ctx.Interp.SyncDebug($"{aType} + {bType} ? {kp.Key}");
                    if (kp.Key.IsAssignableFrom(aType) || kp.Key.IsAssignableFrom(bType))
                    {
                        maxType = kp.Key;
                        break;
                    }
                }
                ;
                if (maxType == null)
                {
                    throw new Exception("Can't cast types");
                }

                if (maxType.IsInterface)
                {
                    return(Ops[maxType](a, b));
                }

                if (maxType.IsPrimitive)
                {
                    a = Convert.ChangeType(a, maxType);
                    b = Convert.ChangeType(b, maxType);
                }
                else if (maxType == typeof(string))
                {
                    a = a.ToString();
                    b = b.ToString();
                }
                //var ao = a == null ? null : (maxType == typeof(object) ? a : Convert.ChangeType(a, maxType));
                //var bo = b == null ? null : (maxType == typeof(object) ? b : Convert.ChangeType(b, maxType));
                var result = Ops[maxType](a, b);
                //ctx.Interp.SyncDebug($"{a}({aType}) {this} {b}({bType}) -> {result}");
                return(result);
            }
            catch (Exception e)
            {
                return(Block.Throw(ctx, e.Message));
            }
        }
예제 #11
0
        public static object CallFunc(VarCtx ctx, object f, object[] args)
        {
            if (ctx.Break == VarCtx.BreakMode.Throw)
            {
                return(null);
            }
            if (!(f is FuncCtx func))
            {
                return(Throw(ctx, $"{f} is not a function"));
            }

            if (new RuntimeException(null, ctx).StackTrace().Count() > 200)
            {
                return(Throw(ctx, $"Stack overflow exception while calling {f}"));
            }

            var funcVarCtx = new VarCtx(ctx, func.ParentScope, func.FunctionProto.Body);

            funcVarCtx.Func = func;
            if (func.FunctionProto.Body != null)
            {
                funcVarCtx.Vars["arguments"] = args ?? new object[0];
                for (int i = 0; i < func.FunctionProto.ArgNames.Length; ++i)
                {
                    if (args != null && i < args.Length)
                    {
                        funcVarCtx.Vars[func.FunctionProto.ArgNames[i]] = args[i];
                    }
                    else
                    {
                        funcVarCtx.Vars[func.FunctionProto.ArgNames[i]] = null;
                    }
                }
                return(func.FunctionProto.Body.RunBlock(funcVarCtx));
            }
            else
            {
                // Native
                try
                {
                    funcVarCtx.CurBlock = new Block()
                    {
                        Type = BlockType.Func
                    };
                    return(func.FunctionProto.Native(funcVarCtx, args));
                }
                catch (Exception e)
                {
                    return(Throw(funcVarCtx, e.ToString()));
                }
            }
        }
예제 #12
0
        public static object SetVal(VarCtx varCtx, string key, object value)
        {
            var callCtx = varCtx;

            while (varCtx != null)
            {
                if (varCtx.Vars.ContainsKey(key))
                {
                    return(varCtx.Vars[key] = value);
                }
                varCtx = varCtx.ParentScope;
            }

            return(Throw(callCtx, $"{key}: undeclared variable"));
        }
예제 #13
0
        public static object Throw(VarCtx varCtx, object v)
        {
            var exc = new RuntimeException(v, varCtx);

            while (varCtx != null)
            {
                varCtx.Break           = VarCtx.BreakMode.Throw;
                varCtx.ScriptException = exc;
                if (varCtx.CurBlock != null && varCtx.CurBlock.Type == BlockType.Try)
                {
                    break;
                }
                varCtx = varCtx.ParentOnStack;
            }
            return(Undefined);
        }
예제 #14
0
        public override object RunBlock(VarCtx ctx)
        {
            ctx.Break           = VarCtx.BreakMode.None;
            ctx.ScriptException = null;
            var result = RunExpr(ctx, Try);

            //ctx.Interp.SyncDebug(ctx.Break);
            if (ctx.Break != VarCtx.BreakMode.Throw)
            {
                return(result);
            }

            DeclareVar(ctx, ExceptionName, ctx.ScriptException);
            ctx.Break = VarCtx.BreakMode.None;
            return(RunExpr(ctx, Catch));
        }
예제 #15
0
            public object Apply(VarCtx varCtx, object dict, object key, object value)
            {
                var a = GetDictVal(varCtx, dict, key);

                if (varCtx.Break != VarCtx.BreakMode.None)
                {
                    return(Undefined);
                }
                var r = op.Arifm(varCtx, a, value);

                SetDictVal(varCtx, dict, key, r);
                if (retOriginal)
                {
                    return(a);
                }
                return(r);
            }
예제 #16
0
 public static object Break(VarCtx varCtx, VarCtx.BreakMode mode)
 {
     while (varCtx != null)
     {
         varCtx.Break = mode;
         if (varCtx.CurBlock?.Type == BlockType.Loop)
         {
             break;
         }
         else if (varCtx.CurBlock == null || varCtx.CurBlock.Type != BlockType.Plain)
         {
             throw new Exception("Break too far"); // should never happen, checks on compilation
         }
         varCtx = varCtx.ParentOnStack;
     }
     return(null);
 }
예제 #17
0
        public override object RunBlock(VarCtx ctx)
        {
            ctx.Break = VarCtx.BreakMode.None;
            object returnValue = null;

            if (Init != null)
            {
                RunExpr(ctx, Init);
            }

            if (ctx.Break == VarCtx.BreakMode.Throw)
            {
                return(null);
            }

            while ((Cond != null) ? CheckCond(ctx, RunExpr(ctx, Cond)) : true)
            {
                if (ctx.Break == VarCtx.BreakMode.Throw)
                {
                    return(null);
                }
                var childCtx = new VarCtx(ctx, ctx, this);
                returnValue = base.RunBlock(childCtx);
                //ctx.Interp.SyncCtx.Send((s) => Debug.Log(childCtx.Break), null);
                if (childCtx.Break == VarCtx.BreakMode.Break || childCtx.Break == VarCtx.BreakMode.Return)
                {
                    break;
                }
                if (ctx.Break == VarCtx.BreakMode.Throw)
                {
                    return(null);
                }
                // "continue" does not need special handling
                if (Inc != null)
                {
                    RunExpr(ctx, Inc);
                    if (ctx.Break == VarCtx.BreakMode.Throw)
                    {
                        return(null);
                    }
                }
            }
            return(returnValue);
        }
예제 #18
0
        public virtual object RunBlock(VarCtx ctx)
        {
            ctx.Break = VarCtx.BreakMode.None;
            object returnValue = null;

            foreach (var expr in Exprs)
            {
                returnValue = RunExpr(ctx, expr);
                if (ctx.Break != VarCtx.BreakMode.None)
                {
                    break;
                }
            }
            if (ctx.CurBlock?.Type == BlockType.Func)
            {
                return(ctx.Func.ReturnValue);
            }
            return(returnValue);
        }
예제 #19
0
            public object Apply(VarCtx varCtx, object value)
            {
                var a = GetVal(varCtx, key);

                if (varCtx.Break != VarCtx.BreakMode.None)
                {
                    return(Undefined);
                }
                var r = op.Arifm(varCtx, a, value);

                SetVal(varCtx, key, r);

                //varCtx.Interp.PauseThread((d) => Debug.Log($"Setvalarifm {key} {a} -> {r} {retOriginal}"), null);
                if (retOriginal)
                {
                    return(a);
                }
                return(r);
            }
예제 #20
0
 protected object RunExpr(VarCtx ctx, BuiltExpression e)
 {
     if (!CompiledCode.ContainsKey(e))
     {
         CompiledCode[e] = Expression.Lambda(e.Expr, RuntimeVarCtx).Compile();
     }
     ctx.Interp.IrqPoll();
     ctx.Interp.Gas -= 1;
     ctx.PC          = e;
     try
     {
         return(CompiledCode[e].DynamicInvoke(ctx));
     }
     catch (Exception ee)
     {
         //ctx.Interp.SyncDebug(ee);
         Throw(ctx, new RuntimeException(ee.Message, ctx));
         return(Undefined);
     }
 }
예제 #21
0
        public FuncCtx PrepareScript(string script)
        {
            var lexer  = new Lexer(script);
            var parser = new Parser(lexer);
            var root   = parser.Parse();

            //Debug.Log(root.Print(""));

            var rb = new Block();

            rb.EAdd(Compile(rb, root));
            rb.Type = Block.BlockType.Func;

            var rc   = new VarCtx(null, null, null, this);
            var main = CreateFunc(rc, "main", new Function {
                Body = rb
            });

            rc.AddVar("main", main);
            return(main);
        }
예제 #22
0
 public static bool CheckCond(VarCtx curCtx, object v)
 {
     //curCtx.Interp.SyncDebug($"check {v}({v?.GetType()})");
     if (v is bool b)
     {
         return(b);
     }
     if (v is long i)
     {
         return(i != 0);
     }
     if (v is float f)
     {
         return(f != 0);
     }
     if (v == Undefined)
     {
         return(false);
     }
     return(v != null);
 }
예제 #23
0
        public static object GetDictVal(VarCtx ctx, object dict, object key)
        {
            if (dict is Dictionary <string, object> d)
            {
                var dkey = GetDictKey(key);
                if (!d.ContainsKey(dkey))
                {
                    return(Undefined);
                }
                return(d[dkey]);
            }
            else if (dict is List <object> arr)
            {
                if (key is string sk)
                {
                    if (sk == "length")
                    {
                        return((long)arr.Count);
                    }
                    if (ctx.Interp.ArrayProto.ContainsKey(sk))
                    {
                        return(DeclareFunc(ctx, ctx.Interp.ArrayProto[sk](arr)));
                    }
                }

                var akey = GetArrayKey(key);
                if (akey >= 0)
                {
                    if (akey < arr.Count)
                    {
                        return(arr[akey]);
                    }
                    return(Undefined);
                }
            }
            return(Throw(ctx, $"Can't read {dict}[{key}]"));
        }
예제 #24
0
 public static object SetDictVal(VarCtx ctx, object dict, object key, object value)
 {
     if (dict is Dictionary <string, object> d)
     {
         var dkey = GetDictKey(key);
         if (dkey != null)
         {
             return(d[dkey] = value);
         }
     }
     else if (dict is List <object> arr)
     {
         var akey = GetArrayKey(key);
         if (akey >= 0)
         {
             if (akey < arr.Count)
             {
                 return(arr[akey] = value);
             }
             return(Undefined);
         }
     }
     return(Throw(ctx, $"Can't write to {dict}[{key}]"));
 }
예제 #25
0
 public VarCtx(VarCtx parentOnStack, VarCtx parScope, Block block) : this(parentOnStack, parScope, block, parScope?.Interp)
 {
 }
예제 #26
0
        public object InvokeBlock(VarCtx parentCtx)
        {
            var childCtx = new VarCtx(parentCtx, parentCtx, this);

            return(RunBlock(childCtx));
        }
예제 #27
0
 public RuntimeException(object msg, VarCtx ctx)
 {
     Message      = msg;
     ThrowContext = ctx;
 }
예제 #28
0
 public static object DeclareVar(VarCtx varCtx, string key, object value)
 {
     return(varCtx.Vars[key] = value);
 }