Ejemplo n.º 1
0
        public double EvaluateFunctionCall(ref int position, uint functionNameHash, int nbParams, double[] param, Stack <int> returnStack, Stack <double> valueStack)
        {
            var found = Functions.TryGetValue(functionNameHash, out var fun);

            if (!found)
            {
                throw new Exception("Tried to call an undefined function '"
                                    + DbgStr(functionNameHash)
                                    + "' at position " + position
                                    + "\r\nKnown functions: " + string.Join(", ", Functions.Keys.Select(DbgStr))
                                    + "\r\nAs a string: " + TryDeref(functionNameHash) + "?"
                                    + "\r\nKnown symbols: " + string.Join(", ", DebugSymbols.Keys.Select(DbgStr)));
            }

            if (fun.Kind != FuncDef.Custom)
            {
                return(EvaluateBuiltInFunction(ref position, fun.Kind, nbParams, param, returnStack, valueStack));
            }

            // handle functions that are defined in the program
            _memory.Variables.PushScope(param);                       // write parameters into new scope
            returnStack.Push(position);                               // set position for 'cret' call
            position = Functions.Get(functionNameHash).StartPosition; // move pointer to start of function
            return(NanTags.VoidReturn());                             // return no value, continue execution elsewhere
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Set a value by name. If no scope has it, then it will be defined in the innermost scope
        /// </summary>
        public void SetValue(uint crushedName, double newValue)
        {
            unchecked
            {
                for (int i = _currentScopeIdx; i >= 0; i--)
                {
                    var current = _scopes[i];
                    if (!current.Get(crushedName, out var oldValue))
                    {
                        continue;
                    }

                    // ReSharper disable once CompareOfFloatsByEqualityOperator
                    if (oldValue == newValue)
                    {
                        return;
                    }
                    if (NanTags.IsAllocated(oldValue))
                    {
                        PotentialGarbage.Add(newValue);
                    }
                    current.Put(crushedName, newValue, true);
                    return;
                }

                // nothing already exists to replace
                _scopes[_currentScopeIdx].Add(crushedName, newValue);
            }
        }
Ejemplo n.º 3
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");
            }
        }
Ejemplo n.º 4
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);
            }
        }
Ejemplo n.º 5
0
        private void HandleMemoryAccess(char action, Stack <double> valueStack, int position, uint varRef, ushort paramCount)
        {
            switch (action)
            {
            case 'g':     // get (adds a value to the stack, false if not set)
                valueStack.Push(_memory.Variables.Resolve(varRef));
                break;

            case 's':     // set
                if (valueStack.Count < 1)
                {
                    throw new Exception("There were no values to save. Did you forget a `return` in a function? Position: " + position);
                }
                _memory.Variables.SetValue(varRef, valueStack.Pop());
                break;

            case 'i':     // is set? (adds a bool to the stack)
                valueStack.Push(NanTags.EncodeBool(_memory.Variables.CanResolve(varRef)));
                break;

            case 'u':     // unset
                _memory.Variables.Remove(varRef);
                break;

            case 'G':     // indexed get
                DoIndexedGet(valueStack, paramCount);
                break;

            default:
                throw new Exception("Unknown memory opcode: '" + action + "'");
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Map parameter names to positional names. This must match the expectations of the interpreter
        /// </summary>
        private static void ParameterPositions(Scope parameterNames, IEnumerable <string> paramNames, NanCodeWriter wr)
        {
            parameterNames.PushScope();
            var i = 0;

            foreach (var paramName in paramNames)
            {
                if (parameterNames.InScope(NanTags.GetCrushedName(paramName)))
                {
                    throw new Exception("Duplicate parameter '" + paramName + "'.\r\n" +
                                        "All parameter names must be unique in a single function definition.");
                }

                var originalReference  = NanTags.GetCrushedName(paramName);
                var parameterReference = Scope.NameFor(i);
                var parameterByteCode  = NanTags.EncodeVariableRef(parameterReference);

                parameterNames.SetValue(originalReference, parameterByteCode);

                wr.AddSymbol(originalReference, paramName);
                wr.AddSymbol(parameterReference, "param[" + i + "]");

                i++;
            }
        }
Ejemplo n.º 7
0
 static Scope()
 {
     posParamHash = new uint[128]; // this limits the number of parameters, so is quite high
     for (int i = 0; i < 128; i++)
     {
         posParamHash[i] = NanTags.GetCrushedName("__p" + i);
     }
 }
Ejemplo n.º 8
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);
            }
        }
Ejemplo n.º 9
0
        public static HashLookup <string> DebugSymbolsForBuiltIns()
        {
            var             tmp = new HashLookup <string>(64);
            Action <string> add = name => { tmp.Add(NanTags.GetCrushedName(name), name); };

            add("="); add("equals"); add(">"); add("<"); add("<>"); add("not-equal");
            add("assert"); add("random"); add("eval"); add("call"); add("not"); add("or");
            add("and"); add("readkey"); add("readline"); add("print"); add("substring");
            add("length"); add("replace"); add("concat"); add("+"); add("-"); add("*");
            add("/"); add("%"); add("()");
            return(tmp);
        }
Ejemplo n.º 10
0
        public void encoding_and_decoding_unsigned_int32()
        {
            unchecked {
                for (int i = 1; i > 0; i += i)
                {
                    uint   original = (uint)i * 3;
                    double enc      = NanTags.EncodeUInt32(original);
                    uint   result   = NanTags.DecodeUInt32(enc);

                    Assert.That(result, Is.EqualTo(original));
                }
            }
        }
Ejemplo n.º 11
0
        public void int32_overflows_the_same_way_as_native()
        {
            unchecked {
                for (int i = 1; i > 0; i += i)
                {
                    int    original = i * 2;
                    double enc      = NanTags.EncodeInt32(original);
                    int    result   = NanTags.DecodeInt32(enc);

                    Assert.That(result, Is.EqualTo(original));
                }
            }
        }
Ejemplo n.º 12
0
        public void doubles_are_interpreted_as_numeric()
        {
            var rnd = new Random();

            for (int i = 0; i < 10000; i++)
            {
                var d   = rnd.NextDouble() / i;
                var inv = 1.0d / d + double.Epsilon;

                Assert.That(NanTags.TypeOf(d), Is.EqualTo(DataType.Number));
                Assert.That(NanTags.TypeOf(inv), Is.EqualTo(DataType.Number));
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Store a new string at the end of memory, and return a string pointer token for it
        /// </summary>
        public double StoreStringAndGetReference(string str)
        {
            // short strings are stack/scope values
            if (str.Length <= 6)
            {
                return(NanTags.EncodeShortStr(str));
            }

            // Longer strings need to be allocated
            var location = encodedTokens.Count;

            var bytes        = Encoding.ASCII.GetBytes(str);
            var headerOpCode = NanTags.EncodeUInt32((uint)bytes.Length);

            encodedTokens.Add(headerOpCode);

            unchecked
            {
                ulong pack = 0;
                int   rem  = 0;
                for (int i = 0; i < bytes.Length; i++)
                {
                    pack += ((ulong)bytes[i]) << rem;

                    rem += 8;
                    if (rem > 56)
                    {
                        encodedTokens.Add(BitConverter.Int64BitsToDouble((long)pack));
                        rem  = 0;
                        pack = 0;
                    }
                }

                if (rem != 0)
                {
                    for (; rem < 64; rem += 8)
                    {
                        pack += ((ulong)'_') << rem;
                    }
                    encodedTokens.Add(BitConverter.Int64BitsToDouble((long)pack));
                }
            }
            var token = NanTags.EncodePointer(location, DataType.PtrString);

            Variables.PotentialGarbage.Add(token);

            return(token);
        }
Ejemplo n.º 14
0
        private int HandleFunctionDefinition(ushort argCount, ushort tokenCount, int position, Stack <double> valueStack)
        {
            var functionNameHash = NanTags.DecodeVariableRef(valueStack.Pop());

            if (Functions.ContainsKey(functionNameHash))
            {
                throw new Exception("Function '" + functionNameHash + "' redefined at " + position + ". Original at " + Functions[functionNameHash]);
            }

            Functions.Add(functionNameHash, new FunctionDefinition {
                StartPosition = position,
                ParamCount    = argCount
            });

            return(position + tokenCount + 1); // + definition length + terminator
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Remove innermost scope, and drop back to the previous one
        /// </summary>
        public void DropScope()
        {
            var last = _scopes[_currentScopeIdx];

            _scopes[_currentScopeIdx] = null;
            _currentScopeIdx--;

            // this could be done on another thread
            foreach (var token in last.Values)
            {
                if (NanTags.IsAllocated(token))
                {
                    PotentialGarbage.Add(token);
                }
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Produce a diagnostic description of the memory layout
        /// </summary>
        public string ToString(HashLookup <string> debugSymbols)
        {
            int index = 0;
            var sb    = new StringBuilder();

            // Try to display static strings meaningfully
            if (NanTags.TypeOf(encodedTokens[0]) == DataType.Opcode)
            {
                index = 1;
                NanTags.DecodeLongOpCode(encodedTokens[0], out var c1, out var c2, out var count);
                if (c1 == 'c' && c2 == 's')
                {
                    sb.AppendLine("Data table: " + count + " tokens (" + (count * 8) + " bytes)");
                    while (index < count)
                    {
                        var length     = NanTags.DecodeUInt32(encodedTokens[index]);
                        var chunkCount = (int)Math.Ceiling(length / 8.0d);
                        sb.Append("    " + index + ": (" + length + ") [");

                        index++;
                        for (var ch = 0; ch < chunkCount; ch++)
                        {
                            var raw = BitConverter.GetBytes(encodedTokens[index++]);
                            sb.Append(MakeSafe(Encoding.ASCII.GetString(raw)));
                        }
                        sb.AppendLine("]");
                    }
                    sb.AppendLine("End of data table");
                }
            }

            // output remaining bytecodes
            for (; index < encodedTokens.Count; index++)
            {
                var token = encodedTokens[index];
                var type  = NanTags.TypeOf(token);
                sb.Append(index.ToString());
                sb.Append(" ");
                sb.Append(type.ToString());
                sb.Append(": ");
                sb.AppendLine(Stringify(token, type, debugSymbols));
            }

            return(sb.ToString());
        }
Ejemplo n.º 17
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));
            }
        }
Ejemplo n.º 18
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();
            }
        }
Ejemplo n.º 19
0
        public string DereferenceString(long position)
        {
            // a string is [NanTag(UInt32): byte length] [string bytes, padded to 8 byte chunks]
            //  1) read the byte length
            var header = encodedTokens[(int)position];

            if (NanTags.TypeOf(header) != DataType.ValUInt32)
            {
                throw new Exception("String header was not a UInt32");
            }
            var length = NanTags.DecodeUInt32(header);

            //  2) calculate chunk count and read the chunks
            var chunkCount = (int)Math.Ceiling(length / 8.0d);
            var rawBytes   = encodedTokens.GetRange((int)position + 1, chunkCount).SelectMany(BitConverter.GetBytes).ToArray();

            //  4) make string (ascii for now, then utf-8?)
            return(Encoding.ASCII.GetString(rawBytes, 0, (int)length));
        }
Ejemplo n.º 20
0
        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));
        }
Ejemplo n.º 21
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();
            }
        }
Ejemplo n.º 22
0
        public void identifier_names_can_be_encoded_and_survive_a_round_trip()
        {
            var enc  = NanTags.EncodeVariableRef("HelloWorld", out var crush);
            var type = NanTags.TypeOf(enc);

            var enc2  = NanTags.EncodeVariableRef("Hel" + "lo" + "Wo" + 'r' + 'l' + 'd', out var crush2);
            var other = NanTags.EncodeVariableRef("HelloWorld2", out var crushOther);

            Console.WriteLine("Crush:   " + crush.ToString("X"));
            Console.WriteLine("Crush:   " + crushOther.ToString("X"));

            var checkCrush = NanTags.DecodeVariableRef(enc);

            Assert.That(checkCrush, Is.EqualTo(crush));

            Assert.That(type, Is.EqualTo(DataType.VariableRef));
            Assert.That(NanTags.AreEqual(enc, enc2), Is.True);
            Assert.That(NanTags.AreEqual(enc, other), Is.False);
            Assert.That(crush, Is.EqualTo(crush2));
            Assert.That(crush, Is.Not.EqualTo(crushOther));
        }
Ejemplo n.º 23
0
        private int PrepareFunctionCall(int position, ushort nbParams, Stack <double> valueStack, Stack <int> returnStack)
        {
            var functionNameHash = NanTags.DecodeVariableRef(valueStack.Pop());

            var param = ReadParams(position, nbParams, valueStack);

            // Evaluate function.
            var evalResult = EvaluateFunctionCall(ref position, functionNameHash, nbParams, param, returnStack, valueStack);

            // Add result on stack as a value.
            if (NanTags.TypeOf(evalResult) != DataType.NoValue)
            {
                valueStack.Push(evalResult);
            }
            else if (NanTags.DecodeNonValue(evalResult) == NonValueType.Unit)
            {
                valueStack.Push(evalResult);
            }

            return(position);
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Symbol mapping for built-in functions
        /// </summary>
        public static HashLookup <FunctionDefinition> BuiltInFunctionSymbols()
        {
            var tmp = new HashLookup <FunctionDefinition>(64);
            Action <string, FuncDef> add = (name, type) => {
                tmp.Add(NanTags.GetCrushedName(name), new FunctionDefinition {
                    Kind = type
                });
            };

            add("=", FuncDef.Equal); add("equals", FuncDef.Equal); add(">", FuncDef.GreaterThan);
            add("<", FuncDef.LessThan); add("<>", FuncDef.NotEqual); add("not-equal", FuncDef.NotEqual);
            add("assert", FuncDef.Assert); add("random", FuncDef.Random); add("eval", FuncDef.Eval);
            add("call", FuncDef.Call); add("not", FuncDef.LogicNot); add("or", FuncDef.LogicOr);
            add("and", FuncDef.LogicAnd); add("readkey", FuncDef.ReadKey); add("readline", FuncDef.ReadLine);
            add("print", FuncDef.Print); add("substring", FuncDef.Substring);
            add("length", FuncDef.Length); add("replace", FuncDef.Replace); add("concat", FuncDef.Concat);
            add("+", FuncDef.MathAdd); add("-", FuncDef.MathSub); add("*", FuncDef.MathProd);
            add("/", FuncDef.MathDiv); add("%", FuncDef.MathMod);
            add("()", FuncDef.UnitEmpty); // empty value marker
            return(tmp);
        }
Ejemplo n.º 25
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);
            }
        }
Ejemplo n.º 26
0
        public void short_identifier_names_get_encoded_uniquely()
        {
            var seen = new HashSet <ulong>();

            for (int i = 0; i < 60; i++)
            {
                var cs = ((char)('A' + i)).ToString();
                NanTags.EncodeVariableRef(cs, out var crush);
                Assert.That(seen.Contains(crush), Is.False);
                seen.Add(crush);
            }

            for (int i = 0; i < 60; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    var cs = ((char)('A' + i)).ToString() + j;
                    NanTags.EncodeVariableRef(cs, out var crush);
                    Assert.That(seen.Contains(crush), Is.False);
                    seen.Add(crush);
                }
            }
        }
Ejemplo n.º 27
0
        // ReSharper disable once UnusedMember.Global
        /// <summary>
        /// Start with source code, and run program to termination
        /// </summary>
        /// <param name="languageInput">Source code</param>
        /// <param name="input">User typing input (for readline / readkey etc)</param>
        /// <param name="output">Print output from the program</param>
        /// <param name="trace">Flag. If true, write the entire interpreter flow to output</param>
        /// <param name="printIL">Flag. If true, write a view of the bytecode IL to output</param>
        /// <param name="traceMemory">Flag. If true, write memory and GC state</param>
        /// <returns>Run time, excluding compile time</returns>
        public static TimeSpan BuildAndRun(string languageInput, TextReader input, TextWriter output,
                                           bool trace, bool printIL, bool traceMemory)
        {
            // Compile
            var sourceCodeReader = new SourceCodeTokeniser();

            var program = sourceCodeReader.Read(languageInput, false);

            if (!program.IsValid)
            {
                output.WriteLine("Program is not well formed"); // TODO: be more helpful
                return(TimeSpan.Zero);
            }

            ToNanCodeCompiler.BaseDirectory = baseDirectory;
            var compiledOutput = ToNanCodeCompiler.CompileRoot(program, debug: false);

            // Load
            var stream = new MemoryStream();

            compiledOutput.WriteToStream(stream);
            stream.Seek(0, SeekOrigin.Begin);
            var memoryModel = new RuntimeMemoryModel(stream);

            if (printIL)
            {
                output.WriteLine("======= BYTE CODE SUMMARY ==========");
                compiledOutput.AddSymbols(ByteCodeInterpreter.DebugSymbolsForBuiltIns());
                output.WriteLine(memoryModel.ToString(compiledOutput.GetSymbols()));
                output.WriteLine("====================================");
            }

            // Execute
            var sw          = new Stopwatch();
            var interpreter = new ByteCodeInterpreter();

            try
            {
                // Init the interpreter.
                interpreter.Init(memoryModel, input, output, debugSymbols: compiledOutput.GetSymbols());

                sw.Start();
                interpreter.Execute(false, trace, false);
                sw.Stop();

                if (traceMemory)
                {
                    output.WriteLine("======== GARBAGE SUMMARY ===========");
                    foreach (var token in memoryModel.Variables.PotentialGarbage)
                    {
                        output.WriteLine(NanTags.Describe(token));
                    }
                    output.WriteLine("====================================");
                }

                return(sw.Elapsed);
            }
            catch (Exception e)
            {
                output.WriteLine("Interpreter stopped at " + interpreter.LastPosition());
                output.WriteLine("Exception : " + e.Message);
                output.WriteLine("\r\n\r\n" + e.StackTrace);
                sw.Stop();
                return(sw.Elapsed);
            }
        }
Ejemplo n.º 28
0
        /// <summary>
        /// Output atom values
        /// </summary>
        private static void EmitLeafNode(Node root, bool debug, Scope parameterNames, Context compileContext, NanCodeWriter wr)
        {
            double leafValue  = 0;
            bool   substitute = false;
            var    valueName  = root.Text;
            var    nameHash   = NanTags.GetCrushedName(valueName);

            if (parameterNames.CanResolve(nameHash))
            {
                substitute = true;
                leafValue  = parameterNames.Resolve(nameHash);
            }

            // An unwrapped variable name?
            if (IsUnwrappedIdentifier(valueName, root, compileContext))
            {
                if (debug)
                {
                    wr.Comment("// treating '" + valueName + "' as an implicit get()");
                }
                if (substitute)
                {
                    wr.Memory('g', leafValue);
                }
                else
                {
                    wr.Memory('g', valueName, 0);
                }

                return;
            }

            if (debug)
            {
                wr.Comment("// Value : \"" + root + "\"\r\n");
                if (substitute)
                {
                    wr.Comment("// Parameter reference redefined as '" + valueName + "'\r\n");
                }
            }

            switch (root.NodeType)
            {
            case NodeType.Numeric:
                wr.LiteralNumber(double.Parse(valueName.Replace("_", "")));
                break;

            case NodeType.StringLiteral:
                wr.LiteralString(valueName);
                break;

            case NodeType.Atom:
                if (valueName == "true")
                {
                    wr.LiteralInt32(-1);
                }
                else if (valueName == "false")
                {
                    wr.LiteralInt32(0);
                }
                else if (substitute)
                {
                    wr.RawToken(leafValue);
                }
                else
                {
                    wr.VariableReference(valueName);
                }
                break;

            default:
                throw new Exception("Unexpected compiler state");
            }
        }
Ejemplo n.º 29
0
 public string DiagnosticString(double token, HashLookup <string> symbols = null)
 {
     return(Stringify(token, NanTags.TypeOf(token), symbols));
 }
Ejemplo n.º 30
0
        /// <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
            });
        }