private string Stringify(double token, DataType type, HashLookup <string> debugSymbols) { switch (type) { case DataType.Invalid: return(""); case DataType.NoValue: return(""); case DataType.VariableRef: var rref = NanTags.DecodeVariableRef(token); if (debugSymbols?.ContainsKey(rref) == true) { return("'" + debugSymbols[rref] + "' (" + rref.ToString("X") + ")"); } return(rref.ToString("X")); case DataType.Opcode: NanTags.DecodeLongOpCode(token, out var ccls, out var cact, out var refr); if (ccls == 'm') { if (debugSymbols?.ContainsKey(refr) == true) { return(ccls + "" + cact + " '" + debugSymbols[refr] + "' (" + refr.ToString("X") + ")"); } } if (ccls == 'i') { if (debugSymbols?.ContainsKey(refr) == true) { return("Incr " + ((sbyte)cact) + " '" + debugSymbols[refr] + "' (" + refr.ToString("X") + ")"); } } NanTags.DecodeOpCode(token, out _, out _, out var p1, out var p2); return(ccls + "" + cact + " (" + p1 + ", " + p2 + ")"); case DataType.ValSmallString: return("[" + NanTags.DecodeShortStr(token) + "]"); case DataType.PtrHashtable: case DataType.PtrGrid: case DataType.PtrSet: case DataType.PtrVector: case DataType.PtrString: case DataType.PtrStaticString: NanTags.DecodePointer(token, out var targ, out _); return(" -> " + targ); case DataType.ValInt32: return(NanTags.DecodeInt32(token).ToString()); case DataType.ValUInt32: return(NanTags.DecodeUInt32(token).ToString()); case DataType.Number: return(token.ToString(CultureInfo.InvariantCulture)); default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } }
public void opcodes_survive_a_round_trip() { double enc1 = NanTags.EncodeOpcode('c', 'j', 123, 0); // control, jump, 123, <unused> double enc2 = NanTags.EncodeOpcode('f', 'd', 3, 40); // function, define, 3 params, 40 opcodes Assert.That(NanTags.TypeOf(enc1), Is.EqualTo(DataType.Opcode)); Assert.That(NanTags.TypeOf(enc2), Is.EqualTo(DataType.Opcode)); NanTags.DecodeOpCode(enc1, out var codeClass, out var codeAction, out var p1, out var p2); Assert.That(codeClass, Is.EqualTo('c')); Assert.That(codeAction, Is.EqualTo('j')); Assert.That(p1, Is.EqualTo(123)); Assert.That(p2, Is.EqualTo(0)); NanTags.DecodeOpCode(enc2, out codeClass, out codeAction, out p1, out p2); Assert.That(codeClass, Is.EqualTo('f')); Assert.That(codeAction, Is.EqualTo('d')); Assert.That(p1, Is.EqualTo(3)); Assert.That(p2, Is.EqualTo(40)); }
/// <summary> /// Main loop. /// Good default for all the flags is `false` /// </summary> /// <param name="resetVars">If true, all scopes are DELETED before running</param> /// <param name="traceExecution">If true, console output of state is written</param> /// <param name="singleStep">If true, the interpreter will run a single step, then return. Internal `eval` statements will run to completion</param> public ExecutionResult Execute(bool resetVars, bool traceExecution, bool singleStep) { double evalResult; _runningVerbose = traceExecution; if (resetVars) { _memory.Variables.Clear(); } while (_position < program.Count) { _stepsTaken++; //if (stepsTaken > 1000) throw new Exception("trap"); // Prevent stackoverflow. // Ex: if(true 1 10 20) if ((_stepsTaken & 127) == 0 && _valueStack.Count > 100) { var oldValues = _valueStack.ToArray(); _valueStack = new Stack <double>(oldValues.Skip(oldValues.Length - 100)); } double word = program[_position]; if (traceExecution) { _output.WriteLine(" stack :" + string.Join(", ", _valueStack.ToArray().Select(t => _memory.DiagnosticString(t, DebugSymbols)))); _output.WriteLine(" #" + _stepsTaken + "; p=" + _position + "; w=" + _memory.DiagnosticString(word, DebugSymbols)); } var type = NanTags.TypeOf(word); switch (type) { case DataType.Invalid: throw new Exception("Unknown code point at " + _position); case DataType.Opcode: // decode opcode and do stuff NanTags.DecodeOpCode(word, out var codeClass, out var codeAction, out var p1, out var p2); ProcessOpCode(codeClass, codeAction, p1, p2, ref _position, _valueStack, _returnStack, word); break; default: _valueStack.Push(word); // these could be raw doubles, encoded real values, or references/pointers break; } _position++; if (singleStep) { return new ExecutionResult { State = ExecutionState.Paused, Result = NanTags.EncodeNonValue(NonValueType.Not_a_Result) } } ; } if (_valueStack.Count != 0) { evalResult = _valueStack.Pop(); } else { evalResult = NanTags.EncodeNonValue(NonValueType.Void); } _valueStack.Clear(); return(new ExecutionResult { State = ExecutionState.Complete, Result = evalResult }); }