public double CastDouble(double encoded) { var type = NanTags.TypeOf(encoded); double result; switch (type) { case DataType.Number: return(encoded); case DataType.ValInt32: return(NanTags.DecodeInt32(encoded)); case DataType.ValUInt32: return(NanTags.DecodeUInt32(encoded)); case DataType.VariableRef: // Follow scope var next = Variables.Resolve(NanTags.DecodeVariableRef(encoded)); return(CastDouble(next)); case DataType.ValSmallString: double.TryParse(NanTags.DecodeShortStr(encoded), out result); return(result); case DataType.PtrStaticString: case DataType.PtrString: NanTags.DecodePointer(encoded, out var target, out _); double.TryParse(DereferenceString(target), out result); return(result); // All the things that can't be meaningfully cast default: return(0.0d); } }
private void DoIndexedGet(Stack <double> valueStack, ushort paramCount) { var target = valueStack.Pop(); var value = _memory.Variables.Resolve(NanTags.DecodeVariableRef(target)); var type = NanTags.TypeOf(value); switch (type) { // Note: Numeric types should read the bit at index // Hashes and arrays do the obvious lookup // Sets return true/false for occupancy case DataType.PtrString: case DataType.PtrStaticString: // get the other indexes. If more than one, build a string out of the bits? // What to do with out-of-range? var str = _memory.DereferenceString(NanTags.DecodePointer(value)); var sb = new StringBuilder(paramCount - 1); for (int i = 0; i < paramCount; i++) { var idx = _memory.CastInt(valueStack.Pop()); if (idx >= 0 && idx < str.Length) { sb.Append(str[idx]); } } var result = _memory.StoreStringAndGetReference(sb.ToString()); valueStack.Push(result); return; default: throw new Exception("Indexing of type '" + type + "' is not yet supported"); } }
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 pointer_encoding_survives_a_round_trip() { var rnd = new Random(); for (int i = 0; i < 10000; i++) { long target = rnd.Next() + ((long)rnd.Next() << 15); var type = DataType.PtrArray_String; var enc = NanTags.EncodePointer(target, type); NanTags.DecodePointer(enc, out var newTarget, out var newType); Assert.That(newTarget, Is.EqualTo(target), "Multiplier: " + i); Assert.That(newType, Is.EqualTo(type)); } }
public int CastInt(double encoded) { int result; var type = NanTags.TypeOf(encoded); switch (type) { case DataType.Invalid: case DataType.Opcode: case DataType.NoValue: return(0); case DataType.VariableRef: // Follow scope var next = Variables.Resolve(NanTags.DecodeVariableRef(encoded)); return(CastInt(next)); case DataType.ValSmallString: int.TryParse(NanTags.DecodeShortStr(encoded), out result); return(result); case DataType.PtrStaticString: case DataType.PtrString: NanTags.DecodePointer(encoded, out var target, out _); int.TryParse(DereferenceString(target), out result); return(result); case DataType.PtrHashtable: case DataType.PtrGrid: case DataType.PtrSet: case DataType.PtrVector: return(0); case DataType.Number: return((int)encoded); case DataType.ValInt32: return(NanTags.DecodeInt32(encoded)); case DataType.ValUInt32: return((int)NanTags.DecodeUInt32(encoded)); default: throw new ArgumentOutOfRangeException(); } }
public string CastString(double encoded) { var type = NanTags.TypeOf(encoded); switch (type) { case DataType.Invalid: return("<invalid value>"); case DataType.Number: return(encoded.ToString(CultureInfo.InvariantCulture)); case DataType.Opcode: return("<Op Code>"); case DataType.NoValue: return(""); case DataType.VariableRef: // Follow scope var next = Variables.Resolve(NanTags.DecodeVariableRef(encoded)); return(CastString(next)); case DataType.ValSmallString: return(NanTags.DecodeShortStr(encoded)); case DataType.PtrStaticString: case DataType.PtrString: NanTags.DecodePointer(encoded, out var target, out _); return(DereferenceString(target)); case DataType.PtrHashtable: case DataType.PtrGrid: case DataType.PtrSet: case DataType.PtrVector: return("<complex type>"); case DataType.ValInt32: return(NanTags.DecodeInt32(encoded).ToString()); case DataType.ValUInt32: return(NanTags.DecodeUInt32(encoded).ToString()); default: throw new ArgumentOutOfRangeException(); } }
public bool CastBoolean(double encoded) { var type = NanTags.TypeOf(encoded); switch (type) { case DataType.Number: return(Math.Abs(encoded) > double.Epsilon); case DataType.ValInt32: return(NanTags.DecodeInt32(encoded) != 0); case DataType.ValUInt32: return(NanTags.DecodeUInt32(encoded) != 0); case DataType.ValSmallString: { var strVal = NanTags.DecodeShortStr(encoded); return(StringTruthyness(strVal)); } case DataType.PtrString: case DataType.PtrStaticString: { NanTags.DecodePointer(encoded, out var ptr, out _); var strVal = DereferenceString(ptr); return(StringTruthyness(strVal)); } case DataType.VariableRef: // Follow scope var next = Variables.Resolve(NanTags.DecodeVariableRef(encoded)); return(CastBoolean(next)); // All the things that can't be meaningfully cast are 'false' default: return(false); } }
private double EvaluateBuiltInFunction(ref int position, FuncDef kind, int nbParams, double[] param, Stack <int> returnStack, Stack <double> valueStack) { switch (kind) { // each element equal to the first case FuncDef.Equal: if (nbParams < 2) { throw new Exception("equals ( = ) must have at least two things to compare"); } return(NanTags.EncodeBool(ListEquals(param))); // Each element smaller than the last case FuncDef.GreaterThan: if (nbParams < 2) { throw new Exception("greater than ( > ) must have at least two things to compare"); } return(NanTags.EncodeBool(FoldGreaterThan(param))); // Each element larger than the last case FuncDef.LessThan: if (nbParams < 2) { throw new Exception("less than ( < ) must have at least two things to compare"); } return(NanTags.EncodeBool(FoldLessThan(param))); // Each element DIFFERENT TO THE FIRST (does not check set uniqueness!) case FuncDef.NotEqual: if (nbParams < 2) { throw new Exception("not-equal ( <> ) must have at least two things to compare"); } return(NanTags.EncodeBool(!ListEquals(param))); case FuncDef.Assert: if (nbParams < 1) { return(NanTags.VoidReturn()); // assert nothing passes } var condition = param.ElementAt(0); if (_memory.CastBoolean(condition) == false) { var msg = ConcatList(param, 1); throw new Exception("Assertion failed: " + msg); } return(NanTags.VoidReturn()); case FuncDef.Random: if (nbParams < 1) { return(rnd.NextDouble()); // 0 params - any size } if (nbParams < 2) { return(rnd.Next(_memory.CastInt(param.ElementAt(0)))); // 1 param - max size } return(rnd.Next(_memory.CastInt(param.ElementAt(0)), _memory.CastInt(param.ElementAt(1)))); // 2 params - range case FuncDef.Eval: var reader = new SourceCodeTokeniser(); var statements = _memory.CastString(param.ElementAt(0)); var programTmp = reader.Read(statements, false); var bin = ToNanCodeCompiler.CompileRoot(programTmp, false); var interpreter = new ByteCodeInterpreter(); interpreter.Init(new RuntimeMemoryModel(bin, _memory.Variables), _input, _output, DebugSymbols); return(interpreter.Execute(false, _runningVerbose, false).Result); case FuncDef.Call: NanTags.DecodePointer(param.ElementAt(0), out var target, out var type); if (type != DataType.PtrString && type != DataType.PtrStaticString) { throw new Exception("Tried to call a function by name, but passed a '" + type + "' at " + position); } // this should be a string, but we need a function name hash -- so calculate it: var strName = _memory.DereferenceString(target); var functionNameHash = NanTags.GetCrushedName(strName); nbParams--; var newParam = param.Skip(1).ToArray(); return(EvaluateFunctionCall(ref position, functionNameHash, nbParams, newParam, returnStack, valueStack)); case FuncDef.LogicNot: if (nbParams != 1) { throw new Exception("'not' should be called with one argument"); } var bval = _memory.CastBoolean(param.ElementAt(0)); return(NanTags.EncodeBool(!bval)); case FuncDef.LogicOr: { bool more = nbParams > 0; int i = 0; while (more) { var bresult = _memory.CastBoolean(param.ElementAt(i)); if (bresult) { return(NanTags.EncodeBool(true)); } i++; more = i < nbParams; } return(NanTags.EncodeBool(false)); } case FuncDef.LogicAnd: { bool more = nbParams > 0; int i = 0; while (more) { var bresult = _memory.CastBoolean(param.ElementAt(i)); if (!bresult) { return(NanTags.EncodeBool(false)); } i++; more = i < nbParams; } return(NanTags.EncodeBool(true)); } case FuncDef.ReadKey: return(_memory.StoreStringAndGetReference(((char)_input.Read()).ToString())); case FuncDef.ReadLine: return(_memory.StoreStringAndGetReference(_input.ReadLine())); case FuncDef.Print: { string lastStr = null; foreach (var v in param) { lastStr = _memory.CastString(v); _output.Write(lastStr); } if (lastStr != "") { _output.WriteLine(); } } return(NanTags.VoidReturn()); case FuncDef.Substring: if (nbParams == 2) { var newString = _memory.CastString(param.ElementAt(0)).Substring(_memory.CastInt(param.ElementAt(1))); return(_memory.StoreStringAndGetReference(newString)); } else if (nbParams == 3) { int start = _memory.CastInt(param.ElementAt(1)); int length = _memory.CastInt(param.ElementAt(2)); string s = _memory.CastString(param.ElementAt(0)).Substring(start, length); return(_memory.StoreStringAndGetReference(s)); } else { throw new Exception("'Substring' should be called with 2 or 3 parameters"); } case FuncDef.Length: return(_memory.CastString(param.ElementAt(0)).Length); case FuncDef.Replace: if (nbParams != 3) { throw new Exception("'Replace' should be called with 3 parameters"); } string exp = _memory.CastString(param.ElementAt(0)); string oldValue = _memory.CastString(param.ElementAt(1)); string newValue = _memory.CastString(param.ElementAt(2)); exp = exp.Replace(oldValue, newValue); return(_memory.StoreStringAndGetReference(exp)); case FuncDef.Concat: var builder = new StringBuilder(); foreach (var v in param) { builder.Append(_memory.CastString(v)); } return(_memory.StoreStringAndGetReference(builder.ToString())); case FuncDef.UnitEmpty: { // valueless marker (like an empty object) return(NanTags.EncodeNonValue(NonValueType.Unit)); } case FuncDef.MathAdd: if (nbParams == 1) { return(param[0]); } return(param.ChainSum()); case FuncDef.MathSub: if (nbParams == 1) { return(-param[0]); } return(param.ChainDifference()); case FuncDef.MathProd: if (nbParams == 1) { throw new Exception("Uniary '*' is not supported"); } return(param.ChainProduct()); case FuncDef.MathDiv: if (nbParams == 1) { throw new Exception("Uniary '/' is not supported"); } return(param.ChainDivide()); case FuncDef.MathMod: if (nbParams == 1) { return(param[0] % 2); } return(param.ChainRemainder()); default: throw new Exception("Unrecognised built-in! Type = " + ((int)kind)); } }