Пример #1
0
        public void OnOpen(WebSocket socket)
        {
            _socket = socket;
            _socket.DataReceived += OnMessage;

            _debugger.GetState(
                out var isRunning, out var programs, out var position, out var watches, out var callStack);

            var message = MondValue.Object();

            message["Type"]        = "InitialState";
            message["Programs"]    = MondValue.Array(programs.Select(Utility.JsonProgram));
            message["Running"]     = isRunning;
            message["Id"]          = position.Id;
            message["StartLine"]   = position.StartLine;
            message["StartColumn"] = position.StartColumn;
            message["EndLine"]     = position.EndLine;
            message["EndColumn"]   = position.EndColumn;
            message["Watches"]     = MondValue.Array(watches.Select(Utility.JsonWatch));

            if (callStack != null)
            {
                message["CallStack"] = _debugger.BuildCallStackArray(callStack);
            }

            Send(Json.Serialize(message));
        }
Пример #2
0
        public MondValue Serialize(MondState state, params MondValue[] args)
        {
            var result = MondValue.Object(state);

            result["$ctor"] = "Regex";
            result["$args"] = MondValue.Array(new MondValue[] { _pattern, _ignoreCase, _multiline });
            return(result);
        }
Пример #3
0
        public MondValue Serialize(MondState state, params MondValue[] args)
        {
            var result = MondValue.Object(state);

            result["$ctor"] = "Color";
            result["$args"] = MondValue.Array(new MondValue[] { Red, Green, Blue, Alpha });
            return(result);
        }
Пример #4
0
        public ArrayTests()
        {
            var arr = MondValue.Array();

            arr.ArrayValue.AddRange(new MondValue[] { 1, 2, 3, 4, 5 });
            _sliceState = new MondState {
                ["arr"] = arr
            };
        }
Пример #5
0
        public static MondValue JsonProgram(ProgramInfo program)
        {
            var obj = MondValue.Object();

            obj["FileName"]    = program.FileName;
            obj["SourceCode"]  = program.DebugInfo.SourceCode;
            obj["FirstLine"]   = FirstLineNumber(program.DebugInfo);
            obj["Breakpoints"] = MondValue.Array(program.Breakpoints.Select(e => MondValue.Number(e)));
            return(obj);
        }
Пример #6
0
        private static MondValue ToMond(MatchCollection matchCollection)
        {
            var value = MondValue.Array();

            foreach (Match m in matchCollection)
            {
                value.AsList.Add(ToMond(m));
            }

            return(value);
        }
Пример #7
0
        public void ArrayIndexer()
        {
            var array = MondValue.Array();

            array.AsList.Add("test");
            array.AsList.Add(123);

            Assert.True(array[0] == "test");
            Assert.True(array[1] == 123);

            Assert.Throws <MondRuntimeException>(() => { var a = array[2]; });
        }
Пример #8
0
        internal MondValue BuildCallStackArray(ReadOnlyCollection <MondDebugContext.CallStackEntry> entries)
        {
            var objs = new List <MondValue>(entries.Count);

            foreach (var entry in entries)
            {
                VisitProgram(entry.Program);

                var programId = FindProgramIndex(entry.Program);
                objs.Add(Utility.JsonCallStackEntry(programId, entry));
            }

            return(MondValue.Array(objs));
        }
Пример #9
0
        public static MondValue WhenAll(MondState state, params MondValue[] tasks)
        {
            AsyncUtil.EnsureAsync();

            var taskArray = AsyncUtil.ToTaskArray(state, tasks);

            var task = Task.WhenAll(taskArray).ContinueWith(t =>
            {
                var array = MondValue.Array();
                array.ArrayValue.AddRange(t.Result);
                return(array);
            });

            return(AsyncUtil.ToObject(task));
        }
Пример #10
0
        public static MondValue JsonValueProperties(MondValue value)
        {
            switch (value.Type)
            {
            case MondValueType.Object:
                var objProperties = value.AsDictionary
                                    .Where(kvp => IsPrimitive(kvp.Key))
                                    .Select(kvp => JsonValueProperty(kvp.Key, kvp.Value));
                return(MondValue.Array(objProperties));

            case MondValueType.Array:
                var arrayProperties = value.AsList
                                      .Select((v, i) => JsonValueProperty(i, v));
                return(MondValue.Array(arrayProperties));

            default:
                return(MondValue.Array());
            }
        }
Пример #11
0
            private MondValue ParseArray()
            {
                var arr = MondValue.Array();

                if (Match(TokenType.ArrayEnd))
                {
                    Take();
                    return(arr);
                }

                arr.AsList.Add(ParseValue());

                while (!Match(TokenType.ArrayEnd))
                {
                    Require(TokenType.Comma);
                    arr.AsList.Add(ParseValue());
                }

                Require(TokenType.ArrayEnd);
                return(arr);
            }
Пример #12
0
        public void Slice()
        {
            var state = new MondState();

            var arr = MondValue.Array();
            var str = MondValue.String("HelloWorld");

            arr.ArrayValue.AddRange(new MondValue[] { 1, 2, 3, 4, 5 });

            Assert.True(str.Slice(1, 3, 1).Equals(MondValue.String("ell")));

            Assert.True(arr.Slice().Enumerate(state).SequenceEqual(arr.Enumerate(state)), "clone");

            Assert.True(arr.Slice(step: -1).Enumerate(state).SequenceEqual(new MondValue[] { 5, 4, 3, 2, 1 }), "reverse");

            Assert.True(arr.Slice(1, 3).Enumerate(state).SequenceEqual(new MondValue[] { 2, 3, 4 }), "range");
            Assert.True(arr.Slice(3, 1).Enumerate(state).SequenceEqual(new MondValue[] { 4, 3, 2 }), "reverse range");

            Assert.True(arr.Slice(0, 0).Enumerate(state).SequenceEqual(new MondValue[] { 1 }), "same start and end");

            Assert.True(arr.Slice(-4, -2).Enumerate(state).SequenceEqual(new MondValue[] { 2, 3, 4 }), "negative range");
            Assert.True(arr.Slice(-2, -4).Enumerate(state).SequenceEqual(new MondValue[] { 4, 3, 2 }), "negative range reverse");

            Assert.True(arr.Slice(step: 2).Enumerate(state).SequenceEqual(new MondValue[] { 1, 3, 5 }), "skip");
            Assert.True(arr.Slice(step: -2).Enumerate(state).SequenceEqual(new MondValue[] { 5, 3, 1 }), "skip negative");

            Assert.Throws <MondRuntimeException>(() => arr.Slice(-6, 0, "out of bounds 1"));
            Assert.Throws <MondRuntimeException>(() => arr.Slice(0, 5, "out of bounds 2"));

            Assert.Throws <MondRuntimeException>(() => arr.Slice(step: 0), "invalid step");

            Assert.Throws <MondRuntimeException>(() => arr.Slice(4, 0, 1), "invalid range");
            Assert.Throws <MondRuntimeException>(() => arr.Slice(0, 4, -1), "invalid range negative");

            Assert.Throws <MondRuntimeException>(() => MondValue.Undefined.Slice(), "slice non-array");

            var empty = MondValue.Array();

            Assert.True(!empty.Slice().Enumerate(state).Any(), "clone empty");
        }
Пример #13
0
        private void VisitProgram(MondProgram program)
        {
            var debugInfo = program.DebugInfo;

            if (IsMissingDebugInfo(debugInfo))
            {
                return;
            }

            int         id;
            ProgramInfo programInfo;

            lock (_sync)
            {
                if (_seenPrograms.Contains(program))
                {
                    return;
                }

                _seenPrograms.Add(program);

                id          = _programs.Count;
                programInfo = new ProgramInfo(program);

                _programs.Add(programInfo);
            }

            var message = MondValue.Object();

            message["Type"]        = "NewProgram";
            message["Id"]          = id;
            message["FileName"]    = programInfo.FileName;
            message["SourceCode"]  = debugInfo.SourceCode;
            message["FirstLine"]   = Utility.FirstLineNumber(debugInfo);
            message["Breakpoints"] = MondValue.Array(programInfo.Breakpoints.Select(e => MondValue.Number(e)));

            Broadcast(message);
        }
Пример #14
0
        public void Contains()
        {
            var arr = MondValue.Array();

            arr.ArrayValue.AddRange(new MondValue[] { 1, 2, 3, 4, 5 });

            Assert.True(arr.Contains(3));
            Assert.False(arr.Contains(10));

            var str = MondValue.String("hello world");

            Assert.True(str.Contains("hello"));
            Assert.False(str.Contains("asdf"));

            var obj = MondValue.Object(new MondState());

            obj["__in"] = new MondFunction((state, args) => args[1].Type == MondValueType.Number);

            Assert.True(obj.Contains(3));
            Assert.False(obj.Contains("hello"));

            Assert.Throws <MondRuntimeException>(() => MondValue.False.Contains(0));
        }
Пример #15
0
        public void ImplicitBool()
        {
            var value = MondValue.Undefined;

            Assert.False(value);

            value = MondValue.Null;
            Assert.False(value);

            value = MondValue.False;
            Assert.False(value);

            value = MondValue.True;
            Assert.True(value);

            value = 0;
            Assert.True(value);

            value = 1;
            Assert.True(value);

            value = double.NaN;
            Assert.False(value);

            value = "hello";
            Assert.True(value);

            value = MondValue.Object();
            Assert.True(value);

            value = MondValue.Array();
            Assert.True(value);

            value = MondValue.Function((state, arguments) => MondValue.Undefined);
            Assert.True(value);
        }
Пример #16
0
        private MondValue Run()
        {
            var functionAddress = PeekCall();
            var program         = functionAddress.Program;
            var code            = program.Bytecode;

            var initialCallDepth  = _callStackSize - 1; // "- 1" to not include values pushed by Call()
            var initialLocalDepth = _localStackSize - 1;
            var initialEvalDepth  = _evalStackSize;

            var ip      = functionAddress.Address;
            var errorIp = 0;

            var   args   = functionAddress.Arguments;
            Frame locals = null;

            try
            {
                while (true)
                {
                    if (Debugger != null)
                    {
                        var skip = _debugSkip;
                        _debugSkip = false;

                        var shouldStopAtStmt =
                            (_debugAction == MondDebugAction.StepInto) ||
                            (_debugAction == MondDebugAction.StepOver && _debugDepth == 0);

                        var shouldBreak =
                            (_debugAlign && program.DebugInfo == null) ||
                            (_debugAlign && program.DebugInfo.IsStatementStart(ip)) ||
                            (Debugger.ShouldBreak(program, ip)) ||
                            (shouldStopAtStmt && program.DebugInfo != null && program.DebugInfo.IsStatementStart(ip));

                        if (!skip && shouldBreak)
                        {
                            DebuggerBreak(program, locals, args, ip, initialCallDepth);
                        }
                    }

                    errorIp = ip;

                    switch (code[ip++])
                    {
                        #region Stack Manipulation
                    case (int)InstructionType.Dup:
                    {
                        Push(Peek());
                        break;
                    }

                    case (int)InstructionType.Dup2:
                    {
                        var value2 = Pop();
                        var value1 = Pop();
                        Push(value1);
                        Push(value2);
                        Push(value1);
                        Push(value2);
                        break;
                    }

                    case (int)InstructionType.Drop:
                    {
                        Pop();
                        break;
                    }

                    case (int)InstructionType.Swap:
                    {
                        var value1 = Pop();
                        var value2 = Pop();
                        Push(value1);
                        Push(value2);
                        break;
                    }

                    case (int)InstructionType.Swap1For2:
                    {
                        var one  = Pop();
                        var two2 = Pop();
                        var two1 = Pop();
                        Push(one);
                        Push(two1);
                        Push(two2);
                        break;
                    }
                        #endregion

                        #region Constants
                    case (int)InstructionType.LdUndef:
                    {
                        Push(MondValue.Undefined);
                        break;
                    }

                    case (int)InstructionType.LdNull:
                    {
                        Push(MondValue.Null);
                        break;
                    }

                    case (int)InstructionType.LdTrue:
                    {
                        Push(MondValue.True);
                        break;
                    }

                    case (int)InstructionType.LdFalse:
                    {
                        Push(MondValue.False);
                        break;
                    }

                    case (int)InstructionType.LdNum:
                    {
                        var numId = ReadInt32(code, ref ip);
                        Push(program.Numbers[numId]);
                        break;
                    }

                    case (int)InstructionType.LdStr:
                    {
                        var strId = ReadInt32(code, ref ip);
                        Push(program.Strings[strId]);
                        break;
                    }

                    case (int)InstructionType.LdGlobal:
                    {
                        Push(Global);
                        break;
                    }
                        #endregion

                        #region Storables
                    case (int)InstructionType.LdLocF:
                    {
                        var index = ReadInt32(code, ref ip);
                        Push(locals.Values[index]);
                        break;
                    }

                    case (int)InstructionType.StLocF:
                    {
                        var index = ReadInt32(code, ref ip);
                        locals.Values[index] = Pop();
                        break;
                    }

                    case (int)InstructionType.LdLoc:
                    {
                        var depth = ReadInt32(code, ref ip);
                        var index = ReadInt32(code, ref ip);

                        if (depth < 0)
                        {
                            Push(args.Get(-depth, index));
                        }
                        else
                        {
                            Push(locals.Get(depth, index));
                        }

                        break;
                    }

                    case (int)InstructionType.StLoc:
                    {
                        var depth = ReadInt32(code, ref ip);
                        var index = ReadInt32(code, ref ip);

                        if (depth < 0)
                        {
                            args.Set(-depth, index, Pop());
                        }
                        else
                        {
                            locals.Set(depth, index, Pop());
                        }

                        break;
                    }

                    case (int)InstructionType.LdFld:
                    {
                        var obj = Pop();
                        Push(obj[program.Strings[ReadInt32(code, ref ip)]]);
                        break;
                    }

                    case (int)InstructionType.StFld:
                    {
                        var obj   = Pop();
                        var value = Pop();

                        obj[program.Strings[ReadInt32(code, ref ip)]] = value;
                        break;
                    }

                    case (int)InstructionType.LdArr:
                    {
                        var index = Pop();
                        var array = Pop();
                        Push(array[index]);
                        break;
                    }

                    case (int)InstructionType.StArr:
                    {
                        var index = Pop();
                        var array = Pop();
                        var value = Pop();
                        array[index] = value;
                        break;
                    }

                    case (int)InstructionType.LdState:
                    {
                        var depth = ReadInt32(code, ref ip);
                        var frame = locals.GetFrame(depth);
                        locals = frame.StoredFrame;

                        PopLocal();
                        PushLocal(locals);

                        var evals = frame.StoredEvals;
                        if (evals != null)
                        {
                            for (var i = evals.Count - 1; i >= 0; i--)
                            {
                                Push(evals[i]);
                            }

                            evals.Clear();
                        }

                        break;
                    }

                    case (int)InstructionType.StState:
                    {
                        var depth = ReadInt32(code, ref ip);
                        var frame = locals.GetFrame(depth);
                        frame.StoredFrame = locals;

                        var initialEvals = _callStackSize > 0 ? PeekCall().EvalDepth : 0;
                        var currentEvals = _evalStackSize;

                        if (currentEvals != initialEvals)
                        {
                            var evals = frame.StoredEvals ?? (frame.StoredEvals = new List <MondValue>());

                            while (currentEvals != initialEvals)
                            {
                                evals.Add(Pop());
                                currentEvals--;
                            }
                        }

                        break;
                    }
                        #endregion

                        #region Object Creation
                    case (int)InstructionType.NewObject:
                    {
                        var obj = MondValue.Object(_state);
                        Push(obj);
                        break;
                    }

                    case (int)InstructionType.NewArray:
                    {
                        var count = ReadInt32(code, ref ip);
                        var array = MondValue.Array();
                        array.ArrayValue.Capacity = count;

                        for (var i = 0; i < count; i++)
                        {
                            array.ArrayValue.Add(default(MondValue));
                        }

                        Push(array);
                        break;
                    }

                    case (int)InstructionType.Slice:
                    {
                        var step  = Pop();
                        var end   = Pop();
                        var start = Pop();
                        var array = Pop();

                        Push(array.Slice(start, end, step));
                        break;
                    }
                        #endregion

                        #region Math
                    case (int)InstructionType.Add:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left + right);
                        break;
                    }

                    case (int)InstructionType.Sub:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left - right);
                        break;
                    }

                    case (int)InstructionType.Mul:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left * right);
                        break;
                    }

                    case (int)InstructionType.Div:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left / right);
                        break;
                    }

                    case (int)InstructionType.Mod:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left % right);
                        break;
                    }

                    case (int)InstructionType.Exp:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left.Pow(right));
                        break;
                    }

                    case (int)InstructionType.BitLShift:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left.LShift(right));
                        break;
                    }

                    case (int)InstructionType.BitRShift:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left.RShift(right));
                        break;
                    }

                    case (int)InstructionType.BitAnd:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left & right);
                        break;
                    }

                    case (int)InstructionType.BitOr:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left | right);
                        break;
                    }

                    case (int)InstructionType.BitXor:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left ^ right);
                        break;
                    }

                    case (int)InstructionType.Neg:
                    {
                        Push(-Pop());
                        break;
                    }

                    case (int)InstructionType.BitNot:
                    {
                        Push(~Pop());
                        break;
                    }
                        #endregion

                        #region Logic
                    case (int)InstructionType.Eq:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left == right);
                        break;
                    }

                    case (int)InstructionType.Neq:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left != right);
                        break;
                    }

                    case (int)InstructionType.Gt:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left > right);
                        break;
                    }

                    case (int)InstructionType.Gte:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left >= right);
                        break;
                    }

                    case (int)InstructionType.Lt:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left < right);
                        break;
                    }

                    case (int)InstructionType.Lte:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(left <= right);
                        break;
                    }

                    case (int)InstructionType.Not:
                    {
                        Push(!Pop());
                        break;
                    }

                    case (int)InstructionType.In:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(right.Contains(left));
                        break;
                    }

                    case (int)InstructionType.NotIn:
                    {
                        var right = Pop();
                        var left  = Pop();
                        Push(!right.Contains(left));
                        break;
                    }
                        #endregion

                        #region Functions
                    case (int)InstructionType.Closure:
                    {
                        var address = ReadInt32(code, ref ip);
                        Push(new MondValue(new Closure(program, address, args, locals)));
                        break;
                    }

                    case (int)InstructionType.Call:
                    {
                        var argCount    = ReadInt32(code, ref ip);
                        var unpackCount = code[ip++];

                        var function = Pop();

                        List <MondValue> unpackedArgs = null;

                        if (unpackCount > 0)
                        {
                            unpackedArgs = UnpackArgs(code, ref ip, argCount, unpackCount);
                        }

                        var returnAddress = ip;

                        if (function.Type == MondValueType.Object)
                        {
                            MondValue[] argArr;

                            if (unpackedArgs == null)
                            {
                                argArr = new MondValue[argCount + 1];

                                for (var i = argCount; i >= 1; i--)
                                {
                                    argArr[i] = Pop();
                                }

                                argArr[0] = function;
                            }
                            else
                            {
                                unpackedArgs.Insert(0, function);
                                argArr = unpackedArgs.ToArray();
                            }

                            if (function.TryDispatch("__call", out var result, argArr))
                            {
                                Push(result);
                                break;
                            }
                        }

                        if (function.Type != MondValueType.Function)
                        {
                            var ldFldBase = ip - 1 - 4 - 1 - 4 - 1;
                            if (ldFldBase >= 0 && code[ldFldBase] == (int)InstructionType.LdFld)
                            {
                                var ldFldIdx     = ldFldBase + 1;
                                var fieldNameIdx = ReadInt32(code, ref ldFldIdx);

                                if (fieldNameIdx >= 0 && fieldNameIdx < program.Strings.Count)
                                {
                                    var fieldName = program.Strings[fieldNameIdx];
                                    throw new MondRuntimeException(RuntimeError.FieldNotCallable, (string)fieldName);
                                }
                            }

                            throw new MondRuntimeException(RuntimeError.ValueNotCallable, function.Type.GetName());
                        }

                        var closure = function.FunctionValue;

                        var argFrame      = function.FunctionValue.Arguments;
                        var argFrameCount = unpackedArgs?.Count ?? argCount;

                        if (argFrame == null)
                        {
                            argFrame = new Frame(1, null, argFrameCount);
                        }
                        else
                        {
                            argFrame = new Frame(argFrame.Depth + 1, argFrame, argFrameCount);
                        }

                        // copy arguments into frame
                        if (unpackedArgs == null)
                        {
                            for (var i = argFrameCount - 1; i >= 0; i--)
                            {
                                argFrame.Values[i] = Pop();
                            }
                        }
                        else
                        {
                            for (var i = 0; i < argFrameCount; i++)
                            {
                                argFrame.Values[i] = unpackedArgs[i];
                            }
                        }

                        switch (closure.Type)
                        {
                        case ClosureType.Mond:
                            PushCall(new ReturnAddress(program, returnAddress, argFrame, _evalStackSize));
                            PushLocal(closure.Locals);

                            program = closure.Program;
                            code    = program.Bytecode;
                            ip      = closure.Address;
                            args    = argFrame;
                            locals  = closure.Locals;

                            if (Debugger != null)
                            {
                                DebuggerCheckCall();
                            }

                            break;

                        case ClosureType.Native:
                            var result = closure.NativeFunction(_state, argFrame.Values);
                            Push(result);
                            break;

                        default:
                            throw new MondRuntimeException(RuntimeError.UnhandledClosureType);
                        }

                        break;
                    }

                    case (int)InstructionType.TailCall:
                    {
                        var argCount    = ReadInt32(code, ref ip);
                        var address     = ReadInt32(code, ref ip);
                        var unpackCount = code[ip++];

                        List <MondValue> unpackedArgs = null;

                        if (unpackCount > 0)
                        {
                            unpackedArgs = UnpackArgs(code, ref ip, argCount, unpackCount);
                        }

                        var returnAddress = PopCall();
                        var argFrame      = returnAddress.Arguments;
                        var argFrameCount = unpackedArgs?.Count ?? argCount;

                        // make sure we have the correct number of values
                        if (argFrameCount != argFrame.Values.Length)
                        {
                            argFrame.Values = new MondValue[argFrameCount];
                        }

                        // copy arguments into frame
                        if (unpackedArgs == null)
                        {
                            for (var i = argFrameCount - 1; i >= 0; i--)
                            {
                                argFrame.Values[i] = Pop();
                            }
                        }
                        else
                        {
                            for (var i = 0; i < argFrameCount; i++)
                            {
                                argFrame.Values[i] = unpackedArgs[i];
                            }
                        }

                        // get rid of old locals
                        PushLocal(PopLocal().Previous);

                        PushCall(new ReturnAddress(returnAddress.Program, returnAddress.Address, argFrame, _evalStackSize));

                        ip = address;
                        break;
                    }

                    case (int)InstructionType.Enter:
                    {
                        var localCount = ReadInt32(code, ref ip);

                        var frame = PopLocal();
                        frame = new Frame(frame?.Depth + 1 ?? 0, frame, localCount);

                        PushLocal(frame);
                        locals = frame;
                        break;
                    }

                    case (int)InstructionType.Leave:
                    {
                        var frame = PopLocal();
                        frame = frame.Previous;

                        PushLocal(frame);
                        locals = frame;
                        break;
                    }

                    case (int)InstructionType.Ret:
                    {
                        var returnAddress = PopCall();
                        PopLocal();

                        program = returnAddress.Program;
                        code    = program.Bytecode;
                        ip      = returnAddress.Address;

                        args   = _callStackSize > 0 ? PeekCall().Arguments : null;
                        locals = _localStackSize > 0 ? PeekLocal() : null;

                        if (_callStackSize == initialCallDepth)
                        {
                            return(Pop());
                        }

                        if (Debugger != null && DebuggerCheckReturn())
                        {
                            DebuggerBreak(program, locals, args, ip, initialCallDepth);
                        }

                        break;
                    }

                    case (int)InstructionType.VarArgs:
                    {
                        var fixedCount = ReadInt32(code, ref ip);
                        var varArgs    = MondValue.Array();

                        for (var i = fixedCount; i < args.Values.Length; i++)
                        {
                            varArgs.ArrayValue.Add(args.Values[i]);
                        }

                        args.Set(args.Depth, fixedCount, varArgs);
                        break;
                    }
                        #endregion

                        #region Branching
                    case (int)InstructionType.Jmp:
                    {
                        var address = ReadInt32(code, ref ip);
                        ip = address;
                        break;
                    }

                    case (int)InstructionType.JmpTrueP:
                    {
                        var address = ReadInt32(code, ref ip);

                        if (Peek())
                        {
                            ip = address;
                        }

                        break;
                    }

                    case (int)InstructionType.JmpFalseP:
                    {
                        var address = ReadInt32(code, ref ip);

                        if (!Peek())
                        {
                            ip = address;
                        }

                        break;
                    }

                    case (int)InstructionType.JmpTrue:
                    {
                        var address = ReadInt32(code, ref ip);

                        if (Pop())
                        {
                            ip = address;
                        }

                        break;
                    }

                    case (int)InstructionType.JmpFalse:
                    {
                        var address = ReadInt32(code, ref ip);

                        if (!Pop())
                        {
                            ip = address;
                        }

                        break;
                    }

                    case (int)InstructionType.JmpTable:
                    {
                        var start = ReadInt32(code, ref ip);
                        var count = ReadInt32(code, ref ip);

                        var endIp = ip + count * 4;

                        var value = Pop();
                        if (value.Type == MondValueType.Number)
                        {
                            var number    = (double)value;
                            var numberInt = (int)number;

                            if (number >= start && number < start + count &&
                                Math.Abs(number - numberInt) <= double.Epsilon)
                            {
                                ip += (numberInt - start) * 4;
                                ip  = ReadInt32(code, ref ip);
                                break;
                            }
                        }

                        ip = endIp;
                        break;
                    }
                        #endregion

                    case (int)InstructionType.Breakpoint:
                    {
                        if (Debugger == null)
                        {
                            break;
                        }

                        DebuggerBreak(program, locals, args, ip, initialCallDepth);

                        // we stop for the statement *after* the debugger statement so we
                        // skip the next break opportunity, otherwise we break twice
                        _debugSkip = true;
                        break;
                    }

                    default:
                        throw new MondRuntimeException(RuntimeError.UnhandledOpcode);
                    }
                }
            }
            catch (Exception e)
            {
                var message = e.Message.Trim();

                // we skip the OOB checks in the stack methods because the CLR has issues eliminating
                // its own checks, so we let it throw and check here for a bit of a speed boost
                if (e is IndexOutOfRangeException)
                {
                    if (_callStackSize >= CallStackCapacity || _localStackSize >= CallStackCapacity || _evalStackSize >= EvalStackCapacity)
                    {
                        message = RuntimeError.StackOverflow;
                    }
                    else if (_callStackSize < 0 || _localStackSize < 0 || _evalStackSize < 0)
                    {
                        message = RuntimeError.StackEmpty;
                    }
                }

                StringBuilder stackTraceBuilder;

                if (e is MondRuntimeException runtimeException &&
                    runtimeException.MondStackTrace != null)
                {
                    stackTraceBuilder = new StringBuilder(runtimeException.MondStackTrace);

                    // check if we are running in a wrapped function
                    var stackTrace   = new System.Diagnostics.StackTrace(e, false);
                    var frames       = stackTrace.GetFrames();
                    var foundWrapper = false;

                    // skip the first frame because it's this method? need to verify
                    for (var i = 1; i < frames.Length; i++)
                    {
                        var method = frames[i].GetMethod();
                        if (method == null)
                        {
                            continue; // ???
                        }
                        var type = method.DeclaringType;

                        // stop at the next call to Machine.Run because it can be recursive
                        if (type == typeof(Machine) && method.Name == "Run")
                        {
                            break;
                        }

                        // the wrapper is a lambda so it's in a compiler generated type, which will be nested
                        var parentType = type.DeclaringType;
                        if (parentType == null)
                        {
                            continue;
                        }

                        // the type and method are compiler generated so they have a weird (and compiler specific) name
                        const string wrapperMagic = "<CheckWrapFunction>";

                        // make sure the type is nested in MondValue and check both the type and method name
                        if (parentType == typeof(MondValue) && (method.Name.Contains(wrapperMagic) || type.Name.Contains(wrapperMagic)))
                        {
                            foundWrapper = true;
                            break;
                        }
                    }

                    // don't show a native transition for wrappers
                    if (!foundWrapper)
                    {
                        stackTraceBuilder.AppendLine("[... native ...]");
                    }
                }
Пример #17
0
        private void UpdateState(MondDebugContext context, int address)
        {
            var program   = context.Program;
            var debugInfo = program.DebugInfo;

            // find out where we are in the source code
            var statement = debugInfo.FindStatement(address);

            if (!statement.HasValue)
            {
                var position = debugInfo.FindPosition(address);

                if (position.HasValue)
                {
                    var line   = position.Value.LineNumber;
                    var column = position.Value.ColumnNumber;
                    statement = new MondDebugInfo.Statement(0, line, column, line, column);
                }
                else
                {
                    statement = new MondDebugInfo.Statement(0, -1, -1, -1, -1);
                }
            }

            // refresh all watches
            List <Watch> watches;

            lock (_sync)
                watches = _watches.ToList();

            foreach (var watch in watches)
            {
                RefreshWatch(_context, watch);
            }

            // apply new state and broadcast it
            MondValue message;

            lock (_sync)
            {
                var stmtValue = statement.Value;
                var programId = FindProgramIndex(program);

                _position = new BreakPosition(
                    programId,
                    stmtValue.StartLineNumber,
                    stmtValue.StartColumnNumber,
                    stmtValue.EndLineNumber,
                    stmtValue.EndColumnNumber);

                message                = MondValue.Object();
                message["Type"]        = "State";
                message["Running"]     = false;
                message["Id"]          = _position.Id;
                message["StartLine"]   = _position.StartLine;
                message["StartColumn"] = _position.StartColumn;
                message["EndLine"]     = _position.EndLine;
                message["EndColumn"]   = _position.EndColumn;
                message["Watches"]     = MondValue.Array(watches.Select(Utility.JsonWatch));
                message["CallStack"]   = BuildCallStackArray(_context.CallStack);
            }

            Broadcast(message);
        }
Пример #18
0
        public MondValue Split(string input, int count = -1, int startat = 0)
        {
            var items = _regex.Split(input, count, startat);

            return(MondValue.Array(items.Select(MondValue.String)));
        }
Пример #19
0
        public void OnMessage(string data)
        {
            MondValue obj;

            try
            {
                obj = Json.Deserialize(data);
            }
            catch
            {
                return;
            }

            try
            {
                switch (obj["type"])
                {
                case "action":
                {
                    var value = (string)obj["action"];

                    if (value == "break")
                    {
                        _debugger.RequestBreak();
                        break;
                    }

                    _debugger.PerformAction(ParseAction(value));
                    ReplyWithOk();
                    break;
                }

                case "stackTrace":
                {
                    var stackFrames = _debugger.GetStackFramesArray();
                    var response    = MondValue.Object();
                    response["stackFrames"] = stackFrames;
                    ReplyWithOk(response);
                    break;
                }

                case "setBreakpoints":
                {
                    var programId   = GetProgramId();
                    var breakpoints = obj["breakpoints"].AsList
                                      .Select(o => (Line: (int)o["line"], Column: o.GetInt("column")));

                    var breakpointStatements = _debugger.SetBreakpoints(programId, breakpoints);

                    var response = MondValue.Object();
                    response["programId"]   = programId;
                    response["breakpoints"] = MondValue.Array(breakpointStatements.Select(Utility.JsonBreakpoint));
                    ReplyWithOk(response);
                    break;
                }

                case "getBreakpointLocations":
                {
                    var programId   = GetProgramId();
                    var startLine   = (int)obj["line"];
                    var startColumn = obj.GetInt("column") ?? int.MinValue;
                    var endLine     = obj.GetInt("endLine") ?? startLine;
                    var endColumn   = obj.GetInt("endColumn") ?? int.MaxValue;

                    var breakpointLocations = _debugger.GetBreakpointLocations(programId, startLine, startColumn, endLine, endColumn);

                    var response = MondValue.Object();
                    response["programId"] = programId;
                    response["locations"] = MondValue.Array(breakpointLocations.Select(Utility.JsonBreakpoint));
                    ReplyWithOk(response);
                    break;
                }

                case "eval":
                {
                    var expression = (string)obj["expression"];
                    var value      = string.IsNullOrEmpty(expression)
                            ? _debugger.GetLocals()
                            : _debugger.Evaluate(expression);

                    var response = MondValue.Object();
                    response["value"]      = value.ToString();
                    response["type"]       = value.Type.GetName();
                    response["properties"] = Utility.JsonValueProperties(value);
                    ReplyWithOk(response);
                    break;
                }

                default:
                {
                    Console.WriteLine("Unhandled message type: " + obj.Type);

                    var response = MondValue.Object();
                    response["status"] = "error";
                    response["error"]  = $"unhandled type {obj["type"]}";
                    ReplyWith(response);

                    break;
                }
                }

                int GetProgramId()
                {
                    var programId = obj["programId"];

                    if (programId.Type == MondValueType.Number)
                    {
                        return((int)programId);
                    }

                    var programPath = obj["programPath"];

                    if (programPath.Type == MondValueType.String)
                    {
                        return(_debugger.FindProgramIndex(programPath));
                    }

                    throw new InvalidOperationException("Both Program ID and Program Path were unspecified");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);

                var response = MondValue.Object();
                response["status"] = "error";
                response["error"]  = e.Message;
                ReplyWith(response);
            }

            void ReplyWithOk(MondValue responseObj = default)
Пример #20
0
        public static MondValue Split([MondInstance] MondValue instance, string separator)
        {
            var values = ((string)instance).Split(new [] { separator }, StringSplitOptions.None);

            return(MondValue.Array(values.Select(v => (MondValue)v)));
        }