diff --git a/bf.html b/bf.html index cad2a6b..2cf029b 100644 --- a/bf.html +++ b/bf.html @@ -14,6 +14,14 @@ +
diff --git a/bf.js b/bf.js index 149b5f6..501910d 100644 --- a/bf.js +++ b/bf.js @@ -39,7 +39,7 @@ window.addEventListener("load",function(){ // memoryview var memoryview=document.getElementById("memoryview"); - var memoryviewmanager=new MemoryView(memoryview.getElementsByClassName("memory-cells")[0],new Uint8Array(30000),0,29999); + var memoryviewmanager=undefined; // buttons var openbutton=document.getElementById("openbutton"); @@ -349,7 +349,7 @@ window.addEventListener("load",function(){ else{ console.log("Execution paused."); } - draw_execution_paused(options.index); + draw_execution_paused(options.index,options.memoryuint8array,options.memory_ptr); continuehandler=options.resume; }); show_execution_only_buttons(true); @@ -460,7 +460,7 @@ window.addEventListener("load",function(){ } }); var execution_location_marker_id=undefined,execution_location_line_id=undefined; - var draw_execution_paused=function(index){ + var draw_execution_paused=function(index,memoryuint8array,memory_ptr){ undraw_execution_paused(); var Range=ace.require('ace/range').Range; var pos=codeEditor.getSession().getDocument().indexToPosition(index); @@ -481,6 +481,8 @@ window.addEventListener("load",function(){ execution_is_paused=true; stepbutton.classList.remove("displaynone"); memoryview.classList.remove("displaynone"); + codeEditor.resize(); + memoryviewmanager=new MemoryView(memoryview.getElementsByClassName("memory-cells")[0],memoryuint8array,0,29999,memory_ptr); }; var undraw_execution_paused=function(){ if(execution_location_marker_id!==undefined)codeEditor.getSession().removeMarker(execution_location_marker_id); @@ -497,6 +499,11 @@ window.addEventListener("load",function(){ execution_is_paused=false; stepbutton.classList.add("displaynone"); memoryview.classList.add("displaynone"); + codeEditor.resize(); + if(memoryviewmanager){ + memoryviewmanager.clear(); + memoryviewmanager=undefined; + } }; diff --git a/jelly-bf-interpreter.js b/jelly-bf-interpreter.js index cd5dc4a..d2c25c1 100644 --- a/jelly-bf-interpreter.js +++ b/jelly-bf-interpreter.js @@ -1,11 +1,11 @@ -JellyBFInterpreter=function(codeString,get_input,put_output,breakpointuint8array,globalpauseuint8array){ +JellyBFInterpreter=function(codeString,get_input,put_output,breakpointuint8array,globalpauseuint8array,memoryuint8array){ this.code=codeString; this.get_input=get_input; this.put_output=put_output; this.breakpointuint8array=breakpointuint8array; this.globalpauseuint8array=globalpauseuint8array; this.memory_cells=30000; - this.memory=new Uint8Array(this.memory_cells); + this.memory=memoryuint8array||new Uint8Array(this.memory_cells); this.memory_ptr=0; this.next_instruction_index=[]; this.loop_pair=[]; @@ -56,33 +56,36 @@ JellyBFInterpreter.prototype.run=function(){ ++this.memory_ptr; } else if(this.code[this.instruction_ptr]==="+"){ - this.memory[this.memory_ptr]=(this.memory[this.memory_ptr]+1)&255; + Atomics.add(this.memory,this.memory_ptr,1); + //this.memory[this.memory_ptr]=(this.memory[this.memory_ptr]+1)&255; } else if(this.code[this.instruction_ptr]==="-"){ - this.memory[this.memory_ptr]=(this.memory[this.memory_ptr]-1)&255; + Atomics.sub(this.memory,this.memory_ptr,1); + //this.memory[this.memory_ptr]=(this.memory[this.memory_ptr]-1)&255; } else if(this.code[this.instruction_ptr]==="["){ - if(this.memory[this.memory_ptr]===0){ + if(Atomics.load(this.memory,this.memory_ptr)===0){ this.instruction_ptr=this.loop_pair[this.instruction_ptr]; } } else if(this.code[this.instruction_ptr]==="]"){ - if(this.memory[this.memory_ptr]!==0){ + if(Atomics.load(this.memory,this.memory_ptr)!==0){ this.instruction_ptr=this.loop_pair[this.instruction_ptr]; } } else if(this.code[this.instruction_ptr]===","){ - this.memory[this.memory_ptr]=this.get_input(); + Atomics.store(this.memory,this.memory_ptr,this.get_input()); + //this.memory[this.memory_ptr]=this.get_input(); } else if(this.code[this.instruction_ptr]==="."){ - this.put_output(this.memory[this.memory_ptr]); + this.put_output(Atomics.load(this.memory,this.memory_ptr)); } else{ throw "Internal error!"; } this.instruction_ptr=this.next_instruction_index[this.instruction_ptr]; - if(this.instruction_ptr!==Number.MAX_SAFE_INTEGER&&Atomics.load(this.breakpointuint8array,this.instruction_ptr)!==0)return {type:JellyBFInterpreter.RunResult.PAUSED_AT_BREAKPOINT,index:this.instruction_ptr}; - if(this.instruction_ptr!==Number.MAX_SAFE_INTEGER&&Atomics.load(this.globalpauseuint8array,0)!==0)return {type:JellyBFInterpreter.RunResult.PAUSED_WITHOUT_BREAKPOINT,index:this.instruction_ptr}; + if(this.instruction_ptr!==Number.MAX_SAFE_INTEGER&&Atomics.load(this.breakpointuint8array,this.instruction_ptr)!==0)return {type:JellyBFInterpreter.RunResult.PAUSED_AT_BREAKPOINT,index:this.instruction_ptr,memory_ptr:this.memory_ptr}; + if(this.instruction_ptr!==Number.MAX_SAFE_INTEGER&&Atomics.load(this.globalpauseuint8array,0)!==0)return {type:JellyBFInterpreter.RunResult.PAUSED_WITHOUT_BREAKPOINT,index:this.instruction_ptr,memory_ptr:this.memory_ptr}; } return {type:JellyBFInterpreter.RunResult.PROGRAM_TERMINATED}; }; \ No newline at end of file diff --git a/jelly-bf-processhandler.js b/jelly-bf-processhandler.js index 5312bb1..02568a2 100644 --- a/jelly-bf-processhandler.js +++ b/jelly-bf-processhandler.js @@ -164,16 +164,18 @@ JellyBFProcessHandler.prototype.executeInteractive=function(options,inputRequest delete options.breakpointBuffer; delete options.globalPauseBuffer; + var memoryBuffer=new SharedArrayBuffer(30000); + var resumer=function(){ that.worker.postMessage({type:"interpret-continue"}); }; var interpretHandler=function(e){ if(e.data.type==="interpret-breakpoint"){ - pausedCallback({breakpoint:true,resume:resumer,index:e.data.index}); + pausedCallback({breakpoint:true,resume:resumer,index:e.data.index,memoryuint8array:new Uint8Array(memoryBuffer),memory_ptr:e.data.memory_ptr}); } else if(e.data.type==="interpret-paused"){ - pausedCallback({breakpoint:false,resume:resumer,index:e.data.index}); + pausedCallback({breakpoint:false,resume:resumer,index:e.data.index,memoryuint8array:new Uint8Array(memoryBuffer),memory_ptr:e.data.memory_ptr}); } }; @@ -205,7 +207,7 @@ JellyBFProcessHandler.prototype.executeInteractive=function(options,inputRequest doneCallback({success:false}); }); - this.worker.postMessage({type:"interpret-interactive",sourcecode:sourcecode,inputbuffer:inputBuffer,outputbuffer:outputBuffer,inputwaitbuffer:inputWaitBuffer,outputwaitbuffer:outputWaitBuffer,breakpointbuffer:breakpointBuffer,globalpausebuffer:globalpauseBuffer,options:options}); + this.worker.postMessage({type:"interpret-interactive",sourcecode:sourcecode,inputbuffer:inputBuffer,outputbuffer:outputBuffer,inputwaitbuffer:inputWaitBuffer,outputwaitbuffer:outputWaitBuffer,breakpointbuffer:breakpointBuffer,globalpausebuffer:globalpauseBuffer,memorybuffer:memoryBuffer,options:options}); } else{ var that=this; diff --git a/jelly-bf-sync.js b/jelly-bf-sync.js index 174d831..d272331 100644 --- a/jelly-bf-sync.js +++ b/jelly-bf-sync.js @@ -84,7 +84,7 @@ var JellyBFSync={ terminate_output(); return true; }, - interpretInteractive:function(str,inputuint8array,outputuint8array,inputwaitint32array,outputwaitint32array,breakpointuint8array,globalpauseuint8array,options,updatedOutputCallback,requestInputCallback){ + interpretInteractive:function(str,inputuint8array,outputuint8array,inputwaitint32array,outputwaitint32array,breakpointuint8array,globalpauseuint8array,memoryuint8array,options,updatedOutputCallback,requestInputCallback){ var WaitArrayId={ READ_HEAD:0, WRITE_HEAD:1, @@ -132,7 +132,7 @@ var JellyBFSync={ Atomics.store(outputwaitint32array,WaitArrayId.WRITE_HEAD,output_write_head+1); updatedOutputCallback(); }; - var instance=new JellyBFInterpreter(str,get_input,put_output,breakpointuint8array,globalpauseuint8array); + var instance=new JellyBFInterpreter(str,get_input,put_output,breakpointuint8array,globalpauseuint8array,memoryuint8array); return { run:function(){ var res=instance.run(); diff --git a/jelly-bf-worker.js b/jelly-bf-worker.js index 04e3604..7e15caf 100644 --- a/jelly-bf-worker.js +++ b/jelly-bf-worker.js @@ -60,8 +60,9 @@ var options=message.options; var breakpointbuffer=message.breakpointbuffer; var globalpausebuffer=message.globalpausebuffer; + var memorybuffer=message.memorybuffer; try{ - interpretstate=JellyBFSync.interpretInteractive(sourcecode, new Uint8Array(inputbuffer), new Uint8Array(outputbuffer), new Int32Array(inputwaitbuffer), new Int32Array(outputwaitbuffer), new Uint8Array(breakpointbuffer), new Uint8Array(globalpausebuffer),options,function(){ + interpretstate=JellyBFSync.interpretInteractive(sourcecode, new Uint8Array(inputbuffer), new Uint8Array(outputbuffer), new Int32Array(inputwaitbuffer), new Int32Array(outputwaitbuffer), new Uint8Array(breakpointbuffer), new Uint8Array(globalpausebuffer),memorybuffer?(new Uint8Array(memorybuffer)):undefined,options,function(){ self.postMessage({type:"output-updated"}); },function(readhead){ self.postMessage({type:"input-requested",readhead:readhead}); @@ -88,10 +89,10 @@ interpretstate=undefined; } else if(ret.type===JellyBFInterpreter.RunResult.PAUSED_AT_BREAKPOINT){ - self.postMessage({type:"interpret-breakpoint",index:ret.index}); + self.postMessage({type:"interpret-breakpoint",index:ret.index,memory_ptr:ret.memory_ptr}); } else if(ret.type===JellyBFInterpreter.RunResult.PAUSED_WITHOUT_BREAKPOINT){ - self.postMessage({type:"interpret-paused",index:ret.index}); + self.postMessage({type:"interpret-paused",index:ret.index,memory_ptr:ret.memory_ptr}); } else{ self.postMessage({type:"interpreterror"}); diff --git a/jelly-bf-worker.max.js b/jelly-bf-worker.max.js index d7eafa9..edd9793 100644 --- a/jelly-bf-worker.max.js +++ b/jelly-bf-worker.max.js @@ -1540,14 +1540,14 @@ var JellyBF_CloseAndAttemptUnrollLoop = function(codeChunks, options) { } }; -JellyBFInterpreter = function(codeString, get_input, put_output, breakpointuint8array, globalpauseuint8array) { +JellyBFInterpreter = function(codeString, get_input, put_output, breakpointuint8array, globalpauseuint8array, memoryuint8array) { this.code = codeString; this.get_input = get_input; this.put_output = put_output; this.breakpointuint8array = breakpointuint8array; this.globalpauseuint8array = globalpauseuint8array; this.memory_cells = 3e4; - this.memory = new Uint8Array(this.memory_cells); + this.memory = memoryuint8array || new Uint8Array(this.memory_cells); this.memory_ptr = 0; this.next_instruction_index = []; this.loop_pair = []; @@ -1589,7 +1589,7 @@ JellyBFInterpreter.RunResult = { }; JellyBFInterpreter.prototype.run = function() { - while (this.instruction_ptr != Number.MAX_SAFE_INTEGER) { + while (this.instruction_ptr !== Number.MAX_SAFE_INTEGER) { if (this.code[this.instruction_ptr] === "<") { if (this.memory_ptr === 0) throw JellyBFInterpreter.RuntimeError.INVALID_MEMORY_ACCESS; --this.memory_ptr; @@ -1597,32 +1597,34 @@ JellyBFInterpreter.prototype.run = function() { if (this.memory_ptr + 1 === this.memory_cells) throw JellyBFInterpreter.RuntimeError.INVALID_MEMORY_ACCESS; ++this.memory_ptr; } else if (this.code[this.instruction_ptr] === "+") { - this.memory[this.memory_ptr] = this.memory[this.memory_ptr] + 1 & 255; + Atomics.add(this.memory, this.memory_ptr, 1); } else if (this.code[this.instruction_ptr] === "-") { - this.memory[this.memory_ptr] = this.memory[this.memory_ptr] - 1 & 255; + Atomics.sub(this.memory, this.memory_ptr, 1); } else if (this.code[this.instruction_ptr] === "[") { - if (this.memory[this.memory_ptr] === 0) { + if (Atomics.load(this.memory, this.memory_ptr) === 0) { this.instruction_ptr = this.loop_pair[this.instruction_ptr]; } } else if (this.code[this.instruction_ptr] === "]") { - if (this.memory[this.memory_ptr] !== 0) { + if (Atomics.load(this.memory, this.memory_ptr) !== 0) { this.instruction_ptr = this.loop_pair[this.instruction_ptr]; } } else if (this.code[this.instruction_ptr] === ",") { - this.memory[this.memory_ptr] = this.get_input(); + Atomics.store(this.memory, this.memory_ptr, this.get_input()); } else if (this.code[this.instruction_ptr] === ".") { - this.put_output(this.memory[this.memory_ptr]); + this.put_output(Atomics.load(this.memory, this.memory_ptr)); } else { throw "Internal error!"; } this.instruction_ptr = this.next_instruction_index[this.instruction_ptr]; if (this.instruction_ptr !== Number.MAX_SAFE_INTEGER && Atomics.load(this.breakpointuint8array, this.instruction_ptr) !== 0) return { type: JellyBFInterpreter.RunResult.PAUSED_AT_BREAKPOINT, - index: this.instruction_ptr + index: this.instruction_ptr, + memory_ptr: this.memory_ptr }; if (this.instruction_ptr !== Number.MAX_SAFE_INTEGER && Atomics.load(this.globalpauseuint8array, 0) !== 0) return { type: JellyBFInterpreter.RunResult.PAUSED_WITHOUT_BREAKPOINT, - index: this.instruction_ptr + index: this.instruction_ptr, + memory_ptr: this.memory_ptr }; } return { @@ -1712,7 +1714,7 @@ var JellyBFSync = { terminate_output(); return true; }, - interpretInteractive: function(str, inputuint8array, outputuint8array, inputwaitint32array, outputwaitint32array, breakpointuint8array, globalpauseuint8array, options, updatedOutputCallback, requestInputCallback) { + interpretInteractive: function(str, inputuint8array, outputuint8array, inputwaitint32array, outputwaitint32array, breakpointuint8array, globalpauseuint8array, memoryuint8array, options, updatedOutputCallback, requestInputCallback) { var WaitArrayId = { READ_HEAD: 0, WRITE_HEAD: 1, @@ -1757,7 +1759,7 @@ var JellyBFSync = { Atomics.store(outputwaitint32array, WaitArrayId.WRITE_HEAD, output_write_head + 1); updatedOutputCallback(); }; - var instance = new JellyBFInterpreter(str, get_input, put_output, breakpointuint8array, globalpauseuint8array); + var instance = new JellyBFInterpreter(str, get_input, put_output, breakpointuint8array, globalpauseuint8array, memoryuint8array); return { run: function() { var res = instance.run(); @@ -1844,8 +1846,9 @@ var JellyBFSync = { var options = message.options; var breakpointbuffer = message.breakpointbuffer; var globalpausebuffer = message.globalpausebuffer; + var memorybuffer = message.memorybuffer; try { - interpretstate = JellyBFSync.interpretInteractive(sourcecode, new Uint8Array(inputbuffer), new Uint8Array(outputbuffer), new Int32Array(inputwaitbuffer), new Int32Array(outputwaitbuffer), new Uint8Array(breakpointbuffer), new Uint8Array(globalpausebuffer), options, function() { + interpretstate = JellyBFSync.interpretInteractive(sourcecode, new Uint8Array(inputbuffer), new Uint8Array(outputbuffer), new Int32Array(inputwaitbuffer), new Int32Array(outputwaitbuffer), new Uint8Array(breakpointbuffer), new Uint8Array(globalpausebuffer), memorybuffer ? new Uint8Array(memorybuffer) : undefined, options, function() { self.postMessage({ type: "output-updated" }); @@ -1887,12 +1890,14 @@ var JellyBFSync = { } else if (ret.type === JellyBFInterpreter.RunResult.PAUSED_AT_BREAKPOINT) { self.postMessage({ type: "interpret-breakpoint", - index: ret.index + index: ret.index, + memory_ptr: ret.memory_ptr }); } else if (ret.type === JellyBFInterpreter.RunResult.PAUSED_WITHOUT_BREAKPOINT) { self.postMessage({ type: "interpret-paused", - index: ret.index + index: ret.index, + memory_ptr: ret.memory_ptr }); } else { self.postMessage({ diff --git a/jelly-memoryview.js b/jelly-memoryview.js index 8169f57..8029030 100644 --- a/jelly-memoryview.js +++ b/jelly-memoryview.js @@ -1,10 +1,11 @@ -var MemoryView=function(root_el,uint8_array,min_index,max_index){ +var MemoryView=function(root_el,uint8_array,min_index,max_index,memory_ptr){ this.root=root_el; this.minIndex=min_index; this.maxIndex=max_index; this.currentIndex=this.minIndex; this.viewLength=1; this.data=uint8_array; + this.ptr=memory_ptr; this.redraw(); var that=this; window.addEventListener("resize",function(){ @@ -17,12 +18,16 @@ MemoryView.prototype.refresh=function(){ var labels=this.root.getElementsByClassName("labelwrapper")[0].getElementsByClassName("label"); for(var i=0;ithis.maxIndex-this.minIndex+1)this.viewLength=this.maxIndex-this.minIndex+1; @@ -45,6 +50,16 @@ MemoryView.prototype.redraw=function(){ this.refresh(); }; +MemoryView.prototype.centerAtIndex=function(index){ + if(indexthis.maxIndex)return false; + index-=(this.viewLength-1)/2; + if(index<0)index=0; + if(index+this.viewLength>this.maxIndex+1)index=this.maxIndex+1-this.viewLength; + this.currentIndex=index; + this.refresh(); + return true; +}; + MemoryView.prototype.goToIndex=function(index){ if(indexthis.maxIndex)return false; if(index