/// <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)); }
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)); }
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)); }
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; }
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)); }
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)); }
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)); }
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")]]); }
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); } }
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); } }
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}\"``"); } }
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))); }