/// <summary>
        /// Compile a line of Yolol into a runnable C# function
        /// </summary>
        /// <param name="line">The line of code to convert</param>
        /// <param name="lineNumber">The number of this line</param>
        /// <param name="maxLines">The max number of lines in a valid program (20, in standard Yolol)</param>
        /// <param name="maxStringLength"></param>
        /// <param name="internalVariableMap">A dictionary used for mapping variables to integers in all lines in this script</param>
        /// <param name="externalVariableMap">A dictionary used for mapping externals to integers in all lines in this script</param>
        /// <param name="staticTypes">Statically known types for variables</param>
        /// <param name="changeDetection"></param>
        /// <returns>A function which runs this line of code. Accepts two sections of memory, internal variables and external variables. Returns the line number to go to next</returns>
        public static Func <ArraySegment <Value>, ArraySegment <Value>, LineResult> Compile(
            this Line line,
            int lineNumber,
            int maxLines,
            int maxStringLength,
            InternalsMap internalVariableMap,
            ExternalsMap externalVariableMap,
            IReadOnlyDictionary <VariableName, Type>?staticTypes = null,
            bool changeDetection = false
            )
        {
            // Locate all accessed variables and load them into the maps
            var stored = new FindAssignedVariables();

            stored.Visit(line);
            var loaded = new FindReadVariables();

            loaded.Visit(line);
            foreach (var name in stored.Names.Concat(loaded.Names).Distinct())
            {
                var dict = name.IsExternal ? (Dictionary <VariableName, int>)externalVariableMap : internalVariableMap;
                if (!dict.TryGetValue(name, out _))
                {
                    dict[name] = dict.Count;
                }
            }

            return(line.Compile(lineNumber, maxLines, maxStringLength, (IReadonlyInternalsMap)internalVariableMap, externalVariableMap, staticTypes, changeDetection));
        }
Exemple #2
0
        private static CompiledResult RunCompiled(Yolol.Grammar.AST.Program ast, int max, int iters)
        {
            var compileTimer = new Stopwatch();

            compileTimer.Start();
            var externalsMap = new ExternalsMap();
            var compiled     = ast.Compile(externalsMap, max, 1024, null, false);

            compileTimer.Stop();

            var externals = new Value[externalsMap.Count];

            Array.Fill(externals, Number.Zero);
            var internals = new Value[compiled.InternalsMap.Count];

            Array.Fill(internals, Number.Zero);

            var execTimer = new Stopwatch();

            execTimer.Start();
            compiled.Run(internals, externals, iters, default);
            execTimer.Stop();

            return(new CompiledResult(compiled.ProgramCounter, compileTimer.Elapsed, execTimer.Elapsed, compiled.InternalsMap, internals, externalsMap, externals));
        }
Exemple #3
0
        public static IMachineState Test(Program program, int iterations, int maxStringLength = 1024, IReadOnlyDictionary <VariableName, Type>?staticTypes = null, bool changeDetection = false)
        {
            var ext       = new ExternalsMap();
            var lines     = Math.Max(20, program.Lines.Count);
            var compiled  = program.Compile(ext, maxLines: lines, maxStringLength: maxStringLength, staticTypes: staticTypes, changeDetection: changeDetection);
            var doneIndex = compiled.InternalsMap.GetValueOrDefault(new VariableName("done"), -1);

            var i = new Value[compiled.InternalsMap.Count];

            Array.Fill(i, new Value((Number)0));

            var e = new Value[ext.Count];

            Array.Fill(e, new Value((Number)0));

            for (var j = 0; j < iterations; j++)
            {
                compiled.Tick(i, e);

                var done = doneIndex < 0 ? Number.Zero : i[doneIndex];
                if (done.ToBool())
                {
                    break;
                }
            }

            return(new CompiledMachineState(compiled, ext, i, e));
        }
        public LinesPerSecond()
        {
            // Pin to one core to reduce benchmarking noise.
            var proc = Process.GetCurrentProcess();

            if (OperatingSystem.IsLinux() || OperatingSystem.IsWindows())
            {
                const int affinity = 1 << 5;
                proc.ProcessorAffinity = (IntPtr)affinity;
            }

            // Make it high priority to reduce benchmarking noise.
            proc.PriorityClass = ProcessPriorityClass.High;

            var ast = Parse(_program);

            var staticTypes = new Dictionary <VariableName, Yolol.Execution.Type> {
                //{ new VariableName("b"), Yolol.Execution.Type.Number },
            };

            _externalsMap = new ExternalsMap();
            var timer = new Stopwatch();

            timer.Start();
            _compiled = ast.Compile(_externalsMap, 20, 1024, staticTypes, true);
            Console.WriteLine($"Compiled in: {timer.Elapsed.TotalMilliseconds}ms");

            _externals = new Value[_externalsMap.Count];
            Array.Fill(_externals, Number.Zero);
            _internals = new Value[_compiled.InternalsMap.Count];
            Array.Fill(_internals, Number.Zero);

            _externals[_externalsMap[new VariableName(":s")]] = new Value("Hello Cylon");
            _externals[_externalsMap[new VariableName(":i")]] = (Number)6;
        }
        /// <summary>
        /// Compile all the lines of a Yolol program into a `CompiledProgram` object
        /// </summary>
        /// <param name="ast"></param>
        /// <param name="externals"></param>
        /// <param name="maxLines"></param>
        /// <param name="maxStringLength"></param>
        /// <param name="staticTypes"></param>
        /// <param name="changeDetection"></param>
        /// <returns></returns>
        public static CompiledProgram Compile(
            this Program ast,
            ExternalsMap externals,
            int maxLines        = 20,
            int maxStringLength = 1024,
            IReadOnlyDictionary <VariableName, Type>?staticTypes = null,
            bool changeDetection = false
            )
        {
            if (maxLines < ast.Lines.Count)
            {
                throw new ArgumentOutOfRangeException(nameof(maxLines), "ast has more than `maxLines` lines");
            }

            var internals = new InternalsMap();

            var compiledLines = new JitLine[maxLines];

            for (var i = 0; i < maxLines; i++)
            {
                var lineNum = i + 1;
                var line    = ast.Lines.ElementAtOrDefault(i) ?? new Line(new StatementList());
                compiledLines[i] = new JitLine(line.Compile(lineNum, maxLines, maxStringLength, internals, externals, staticTypes, changeDetection));
            }

            return(new CompiledProgram(internals, compiledLines));
        }
Exemple #6
0
 public EasyMachineState(Value[] i, Value[] e, InternalsMap internals, ExternalsMap externals, int pc, ChangeSet set)
 {
     Internals      = i;
     Externals      = e;
     InternalMap    = internals;
     ExternalMap    = externals;
     ProgramCounter = pc;
     ChangeSet      = set;
 }
Exemple #7
0
 public CompiledResult(
     int programCounter,
     TimeSpan compile, TimeSpan execute,
     IReadonlyInternalsMap internalsMap, IReadOnlyList <Value> internals,
     ExternalsMap externalsMap, IReadOnlyList <Value> externals)
 {
     _internalsMap  = internalsMap;
     _internals     = internals;
     _externalsMap  = externalsMap;
     _externals     = externals;
     Prepare        = compile;
     Execute        = execute;
     ProgramCounter = programCounter;
 }
        public IExecutionState Prepare(Yolol.Grammar.AST.Program program, string done)
        {
            var internalsMap = new InternalsMap();
            var externalsMap = new ExternalsMap();
            var lines        = new List <Func <ArraySegment <Value>, ArraySegment <Value>, int> >();

            for (var i = 0; i < program.Lines.Count; i++)
            {
                lines.Add(program.Lines[i].Compile(
                              i + 1,
                              Math.Max(20, program.Lines.Count),
                              internalsMap,
                              externalsMap
                              ));
            }

            return(new ExecutionState(lines, internalsMap, externalsMap, done));
        }
Exemple #9
0
        public async Task <IEnumerable <IExecutionState> > Prepare(IEnumerable <Yolol.Grammar.AST.Program> programs, string done = ":done")
        {
            var externalsMap = new ExternalsMap();

            // Compile all programs first
            var compiled = (from program in programs
                            let c = program.Compile(externalsMap, Math.Max(20, program.Lines.Count), MaxStringLength, null, true)
                                    select(c, program)
                            ).ToList();

            // Create array to hold externals (common to all contexts)
            var externals = new Value[externalsMap.Count];

            Array.Fill(externals, new Value((Number)0));

            // Build an execution state for all programs
            return(from item in compiled
                   select new ExecutionState(item.c, item.program, externalsMap, done, externals));
        }
Exemple #10
0
        public static IMachineState Test(string line, int lineNumber = 1, int maxStringLength = 1024, IReadOnlyDictionary <VariableName, Type>?staticTypes = null, bool changeDetection = false)
        {
            var internals = new InternalsMap();
            var externals = new ExternalsMap();

            var ast      = Parse(line);
            var compiled = ast.Lines[0].Compile(lineNumber, 20, maxStringLength, internals, externals, staticTypes, changeDetection);

            var i = new Value[internals.Count];

            Array.Fill(i, new Value((Number)0));
            var e = new Value[externals.Count];

            Array.Fill(e, new Value((Number)0));

            var r = compiled.Invoke(i, e);

            return(new EasyMachineState(i, e, internals, externals, r.ProgramCounter, r.ChangeSet));
        }
Exemple #11
0
        public CompareInterpreter()
        {
            _ast = Parse(
                ":done++ b=97 c=89",
                ":o++ :done++",
                ":done++",
                "i=127-1 _=(i/3%1==0)*i/3>1+(i/5%1==0)*i/5>1+(i/7%1==0)*i/7>1 a=i/11%1==0",
                "_+=a*i/11>1+(i/13%1==0)*i/13>1+(i/17%1==0)*i/17>1+(i/19%1==0)*i/19>1",
                "_+=(i/23%1==0)*i/23>1+(i/29%1==0)*i/29>1+(i/31%1==0)*i/31>1a=i/37%1==0",
                "_+=a*i/37>1+(i/41%1==0)*i/41>1+(i/43%1==0)*i/43>1+(i/47%1==0)*i/47>1",
                "_+=(i/53%1==0)*i/53>1+(i/59%1==0)*i/59>1+(i/61%1==0)*i/61>1a=i/67%1==0",
                "_+=a*i/67>1+(i/71%1==0)*i/71>1+(i/73%1==0)*i/73>1+(i/79%1==0)*i/79>1",
                "_+=(i/83%1==0)*i/83>1+(i/c%1==0)*i/c>1+(i/b%1==0)*i/b>1:o+=_<1:done++",
                "z=:o :done++goto4"
                );

            _network = new Network((Number)1, (Number)2, (Number)0);
            _state   = new MachineState(_network);

            var types = new Dictionary <VariableName, Yolol.Execution.Type> {
                { new VariableName("a"), Yolol.Execution.Type.Number },
                { new VariableName("b"), Yolol.Execution.Type.Number },
                { new VariableName("c"), Yolol.Execution.Type.Number },
                { new VariableName("d"), Yolol.Execution.Type.Number },
                { new VariableName("e"), Yolol.Execution.Type.Number },
                { new VariableName("f"), Yolol.Execution.Type.Number },
            };
            var internalsPerLine = new InternalsMap();
            var externalsPerLine = new ExternalsMap();

            _compiledLines = new Func <ArraySegment <Value>, ArraySegment <Value>, LineResult> [_ast.Lines.Count];
            for (var i = 0; i < _ast.Lines.Count; i++)
            {
                _compiledLines[i] = _ast.Lines[i].Compile(i + 1, 20, 1024, internalsPerLine, externalsPerLine, types);
            }

            _internals = new Value[internalsPerLine.Count];
            _externals = new Value[externalsPerLine.Count];

            _compiledProgramLine = _ast.Compile(new ExternalsMap(), 20, 1024, types);
        }
        public void RunUntilChanged()
        {
            var ast  = TestHelpers.Parse(":a=1", ":b=2", ":c=3", ":d=1");
            var ext  = new ExternalsMap();
            var prog = ast.Compile(ext, 4, 1024, null, true);

            var i = new Value[prog.InternalsMap.Count];

            Array.Fill(i, new Value((Number)0));
            var e = new Value[ext.Count];

            Array.Fill(e, new Value((Number)0));

            var count = prog.Run(i, e, 4, ext.ChangeSetKey(new VariableName(":c")));

            Assert.AreEqual(3, count);
            Assert.AreEqual((Number)1, e[ext[new VariableName(":a")]]);
            Assert.AreEqual((Number)2, e[ext[new VariableName(":b")]]);
            Assert.AreEqual((Number)3, e[ext[new VariableName(":c")]]);
            Assert.AreEqual((Number)0, e[ext[new VariableName(":d")]]);
        }
Exemple #13
0
        public void FuzzOverflow()
        {
            var ast = TestHelpers.Parse(
                "b=-9223372036854775.808 b%=-0.001"
                );

            var lines        = Math.Max(20, ast.Lines.Count);
            var externalsMap = new ExternalsMap();
            var compiled     = ast.Compile(externalsMap, lines, 1024, null, false);

            var externals = new Value[externalsMap.Count];

            Array.Fill(externals, Number.Zero);
            var internals = new Value[compiled.InternalsMap.Count];

            Array.Fill(internals, Number.Zero);

            for (var i = 0; i < 1502; i++)
            {
                compiled.Tick(internals, externals);
            }
        }
Exemple #14
0
        public void FuzzPlayground()
        {
            var ast = TestHelpers.Parse(
                "a=10 b=a-a--"
                );

            var lines        = Math.Max(20, ast.Lines.Count);
            var externalsMap = new ExternalsMap();
            var compiled     = ast.Compile(externalsMap, lines, 1024, null, false);

            var externals = new Value[externalsMap.Count];

            Array.Fill(externals, Number.Zero);
            var internals = new Value[compiled.InternalsMap.Count];

            Array.Fill(internals, Number.Zero);

            for (var i = 0; i < 1; i++)
            {
                compiled.Tick(internals, externals);
            }
        }
Exemple #15
0
        private static void RunTestFile(FileInfo file)
        {
            var outerTimer = new Stopwatch();

            // Parse file
            var txt = File.ReadAllText(file.FullName);

            outerTimer.Start();
            var ast = Parse(txt);

            outerTimer.Stop();
            Console.WriteLine($" - Parsed:\t{outerTimer.Elapsed.TotalMilliseconds} ms");

            // Set up the compiler
            var externalsMap = new ExternalsMap();

            // Compile - program has 20 line, or however many are in the file. Whichever is more.
            outerTimer.Start();
            var compiled = ast.Compile(externalsMap, Math.Max(20, ast.Lines.Count));

            outerTimer.Stop();

            // Write out time to compile program
            Console.WriteLine($" - Compiled:\t{outerTimer.Elapsed.TotalMilliseconds} ms");

            // Set up runtime
            var externals = new Value[externalsMap.Count];

            Array.Fill(externals, Number.Zero);
            var internals = new Value[compiled.InternalsMap.Count];

            Array.Fill(internals, Number.Zero);
            var outputIdx = externalsMap[new VariableName(":output")];

            var iterations = 500000;

            // Run the program for some time
            var totalLineCount = 0ul;
            var samples        = new List <double>();

            outerTimer.Restart();
            while (outerTimer.Elapsed < Duration)
            {
                var innerTimer = new Stopwatch();
                innerTimer.Start();
                compiled.Run(internals, externals, iterations, default);
                innerTimer.Stop();
                totalLineCount += (ulong)iterations;

                // Calculate how many lines-per-second that was and store in lps buffer
                var lps = iterations / innerTimer.Elapsed.TotalSeconds;
                samples.Add(lps);

                // Adjust iteration count so next batch takes about 0.5 seconds
                iterations = (int)(lps * 0.5);
            }

            // Calculate average LPS over the last 10 samples (this should cut out any weirdness in the first few samples as things are getting going)
            var avg = samples.Take(10).Average();

            // Calculate standard deviation over entire set
            var s      = samples.AsEnumerable().ToList();
            var sum    = s.Sum(d => Math.Pow(d - avg, 2));
            var stdDev = Math.Sqrt(sum / (samples.Count - 1));

            // Print out some stats
            Console.WriteLine($" - Total:\t{totalLineCount:#,#} lines");
            Console.WriteLine($" - Average:\t{avg:#,##0} l/s");
            Console.WriteLine($" - StdDev:\t{stdDev:#,##0}");

            // Verify final result
            var output = externals[outputIdx];

            if (output != "ok")
            {
                Console.WriteLine($" - FAILED! Expected `:OUTPUT==\"ok\"`, got ``:OUTPUT==\"{output}\"``");
            }
        }
Exemple #16
0
        public static void Compare(Program ast, int ticks)
        {
            // Compile setup
            var ext       = new ExternalsMap();
            var lines     = Math.Max(20, ast.Lines.Count);
            var compiled  = ast.Compile(ext, lines);
            var internals = new Value[compiled.InternalsMap.Count];

            Array.Fill(internals, new Value((Number)0));
            var externals = new Value[ext.Count];

            Array.Fill(externals, new Value((Number)0));

            // Interpret setup
            var maxLines = Math.Max(20, ast.Lines.Count);

            int CheckPc(int pc)
            {
                if (pc >= maxLines)
                {
                    return(0);
                }
                if (pc < 0)
                {
                    return(0);
                }
                return(pc);
            }

            var pc = 0;
            var nt = new DeviceNetwork();
            var st = new MachineState(nt, (ushort)maxLines);

            for (var i = 0; i < ticks; i++)
            {
                if (pc >= ast.Lines.Count)
                {
                    pc++;
                }
                else
                {
                    try
                    {
                        pc = ast.Lines[pc].Evaluate(pc, st);
                    }
                    catch (ExecutionException)
                    {
                        pc++;
                    }
                }
                pc = CheckPc(pc);

                compiled.Tick(internals, externals);

                foreach (var item in compiled.InternalsMap)
                {
                    var interpretedVal = st.GetVariable(item.Key.Name).Value;
                    var compiledVal    = internals[item.Value];
                    Assert.AreEqual(interpretedVal, compiledVal, $"varname:{item.Key} ticks:{i}");
                }

                foreach (var item in ext)
                {
                    var interpretedVal = st.GetVariable(item.Key.Name).Value;
                    var compiledVal    = externals[item.Value];
                    Assert.AreEqual(interpretedVal, compiledVal, $"varname:{item.Key} ticks:{i}");
                }
            }
        }
 public static CompiledProgramState Compile(Program program, ExternalsMap externalsMap)
 {
     return(new CompiledProgramState(program.Compile(externalsMap, program.Lines.Count, maxStringLength: MaxStringLength)));
 }