Example #1
0
        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);
            }
        }
Example #2
0
        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");
            }
        }
Example #3
0
        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);
            }
        }
Example #4
0
        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));
            }
        }
Example #5
0
        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();
            }
        }
Example #6
0
        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();
            }
        }
Example #7
0
        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);
            }
        }
Example #8
0
        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));
            }
        }