Compare commits

..

No commits in common. "master" and "new-volt" have entirely different histories.

68 changed files with 976 additions and 1426 deletions

42
Gemfile
View File

@ -1,21 +1,41 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gem "opal" gem 'volt', '0.9.5.pre4'
gem 'opal-sprockets'
gem 'opal-browser'
gem "rubyx" , "0.6" , path: "../rubyx" # volt uses mongo as the default data store.
gem 'volt-mongo', '~> 0.1.0'
gem "rx-file" , :git => "https://github.com/ruby-x/rx-file" gem "parslet" , git: "https://github.com/salama/parslet.git"
#gem "salama" , git: "https://github.com/salama/salama.git"
gem "salama" , path: "../salama"
gem "salama-reader" , git: "https://github.com/salama/salama-reader.git"
gem "salama-arm" , git: "https://github.com/salama/salama-arm.git"
gem "salama-object-file" , git: "https://github.com/salama/salama-object-file.git"
gem "susy" , "2.2.5"
gem "sass" # Asset compilation gems, they will be required when needed.
gem 'csso-rails', '~> 0.3.4', require: false
gem 'uglifier', '>= 2.4.0', require: false
#gem "foundation" , :github => "zurb/foundation"
group :test do group :test do
# Testing dependencies # Testing dependencies
gem "minitest" gem "minitest"
gem 'rspec' gem 'rspec', '~> 3.2.0'
gem 'capybara' gem 'opal-rspec', '~> 0.4.2'
gem 'selenium-webdriver' gem 'capybara', '~> 2.4.2'
gem 'chromedriver2-helper' gem 'selenium-webdriver', '~> 2.43.0'
gem 'poltergeist' gem 'chromedriver2-helper', '~> 0.0.8'
gem 'poltergeist', '~> 1.5.0'
end
# Server for MRI
platform :mri, :mingw do
# The implementation of ReadWriteLock in Volt uses concurrent ruby and ext helps performance.
gem 'concurrent-ruby-ext', '~> 0.8.0'
# Thin is the default volt server, Puma is also supported
gem 'thin', '~> 1.6.0'
gem 'bson_ext', '~> 1.9.0'
end end

View File

@ -1,120 +1,186 @@
GIT GIT
remote: https://github.com/ruby-x/rx-file remote: https://github.com/salama/parslet.git
revision: 7c4a5546136d1bad065803da91778b209c18cb4d revision: beeb9b441a9ade1504f7f0e848d805e36a02c544
specs: specs:
rx-file (0.3.0) parslet (1.7.0)
GIT
remote: https://github.com/salama/salama-arm.git
revision: 0bd5091e3f284ecf040e0086a41d2449cd5afb7a
specs:
salama-arm (0.0.1)
GIT
remote: https://github.com/salama/salama-object-file.git
revision: fbae6a02764dbe97e01e4833f9ffffe09879b100
specs:
salama-object-file (0.2.0)
GIT
remote: https://github.com/salama/salama-reader.git
revision: 841592c667acea1e796f950851262e6938b231bc
specs:
salama-reader (0.2.0)
parslet (~> 1.7.0)
PATH PATH
remote: ../rubyx remote: ../salama
specs: specs:
rubyx (0.6.0) salama (0.2.0)
parser (~> 2.3.0) salama-object-file (~> 0.2)
rx-file (~> 0.3) salama-reader (~> 0.2)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
addressable (2.6.0) bcrypt (3.1.10)
public_suffix (>= 2.0.2, < 4.0) bson (1.9.2)
ast (2.4.0) bson_ext (1.9.2)
capybara (3.13.2) bson (~> 1.9.2)
addressable capybara (2.4.4)
mini_mime (>= 0.1.3) mime-types (>= 1.16)
nokogiri (~> 1.8) nokogiri (>= 1.3.3)
rack (>= 1.6.0) rack (>= 1.0.0)
rack-test (>= 0.6.3) rack-test (>= 0.5.4)
regexp_parser (~> 1.2) xpath (~> 2.0)
xpath (~> 3.2) childprocess (0.5.6)
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11) ffi (~> 1.0, >= 1.0.11)
chromedriver2-helper (0.0.10) chromedriver2-helper (0.0.8)
nokogiri nokogiri
cliver (0.3.2) cliver (0.3.2)
concurrent-ruby (1.1.4) coderay (1.1.0)
diff-lcs (1.3) concurrent-ruby (0.8.0)
ffi (1.10.0) ref (~> 1.0, >= 1.0.5)
concurrent-ruby-ext (0.8.0)
concurrent-ruby (~> 0.8.0)
configurations (2.0.0)
csso-rails (0.3.4)
execjs (>= 1)
daemons (1.2.3)
diff-lcs (1.2.5)
eventmachine (1.0.8)
execjs (2.5.2)
faye-websocket (0.10.0)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.5.1)
ffi (1.9.10)
hike (1.2.3) hike (1.2.3)
mini_mime (1.0.1) json (1.8.3)
mini_portile2 (2.4.0) listen (3.0.3)
minitest (5.11.3) rb-fsevent (>= 0.9.3)
nokogiri (1.10.1) rb-inotify (>= 0.9)
mini_portile2 (~> 2.4.0) method_source (0.8.2)
opal (0.11.4) mime-types (2.6.1)
ast (>= 2.3.0) mini_portile (0.6.2)
minitest (5.8.0)
mongo (1.9.2)
bson (~> 1.9.2)
multi_json (1.11.2)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
opal (0.8.0)
hike (~> 1.2) hike (~> 1.2)
parser (= 2.3.3.1)
sourcemap (~> 0.1.0) sourcemap (~> 0.1.0)
opal-browser (0.2.0)
opal
paggio
opal-sprockets (0.4.2.0.11.0.3.1)
opal (~> 0.11.0)
sprockets (~> 3.1) sprockets (~> 3.1)
tilt (>= 1.4) tilt (>= 1.4)
paggio (0.2.6) opal-rspec (0.4.3)
parser (2.3.3.1) opal (>= 0.7.0, < 0.9)
ast (~> 2.2) poltergeist (1.5.1)
poltergeist (1.18.1) capybara (~> 2.1)
capybara (>= 2.1, < 4)
cliver (~> 0.3.1) cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0) websocket-driver (>= 0.2.0)
public_suffix (3.0.3) pry (0.10.1)
rack (2.0.6) coderay (~> 1.1.0)
rack-test (1.1.0) method_source (~> 0.8.1)
rack (>= 1.0, < 3) slop (~> 3.4)
rb-fsevent (0.10.3) rack (1.5.5)
rb-inotify (0.10.0) rack-test (0.6.3)
ffi (~> 1.0) rack (>= 1.0)
regexp_parser (1.3.0) rb-fsevent (0.9.5)
rspec (3.8.0) rb-inotify (0.9.5)
rspec-core (~> 3.8.0) ffi (>= 0.5.0)
rspec-expectations (~> 3.8.0) ref (1.0.5)
rspec-mocks (~> 3.8.0) rspec (3.2.0)
rspec-core (3.8.0) rspec-core (~> 3.2.0)
rspec-support (~> 3.8.0) rspec-expectations (~> 3.2.0)
rspec-expectations (3.8.2) rspec-mocks (~> 3.2.0)
rspec-core (3.2.3)
rspec-support (~> 3.2.0)
rspec-expectations (3.2.1)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0) rspec-support (~> 3.2.0)
rspec-mocks (3.8.0) rspec-mocks (3.2.1)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0) rspec-support (~> 3.2.0)
rspec-support (3.8.0) rspec-support (3.2.2)
rubyzip (1.2.2) rubyzip (1.1.7)
sass (3.7.3) sass (3.4.16)
sass-listen (~> 4.0.0) selenium-webdriver (2.43.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
selenium-webdriver (3.141.0)
childprocess (~> 0.5) childprocess (~> 0.5)
rubyzip (~> 1.2, >= 1.2.2) multi_json (~> 1.0)
rubyzip (~> 1.0)
websocket (~> 1.0)
slop (3.6.0)
sourcemap (0.1.1) sourcemap (0.1.1)
sprockets (3.7.2) sprockets (3.2.0)
concurrent-ruby (~> 1.0) rack (~> 1.0)
rack (> 1, < 3) susy (2.2.5)
tilt (2.0.9) sass (>= 3.3.0, < 3.5)
websocket-driver (0.7.0) thin (1.6.3)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0)
rack (~> 1.0)
thor (0.19.1)
tilt (2.0.1)
uglifier (2.7.1)
execjs (>= 0.3.0)
json (>= 1.8.0)
volt (0.9.5.pre4)
bcrypt (~> 3.1.9)
bundler (>= 1.5)
concurrent-ruby (= 0.8.0)
configurations (~> 2.0.0.pre)
faye-websocket (~> 0.10.0)
listen (~> 3.0.1)
opal (~> 0.8.0)
pry (~> 0.10.1)
rack (~> 1.5.0)
sass (~> 3.4.15)
thor (~> 0.19.0)
volt-mongo (0.1.1)
mongo (~> 1.9.0)
websocket (1.2.2)
websocket-driver (0.6.2)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3) websocket-extensions (0.1.2)
xpath (3.2.0) xpath (2.0.0)
nokogiri (~> 1.8) nokogiri (~> 1.3)
PLATFORMS PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
capybara bson_ext (~> 1.9.0)
chromedriver2-helper capybara (~> 2.4.2)
chromedriver2-helper (~> 0.0.8)
concurrent-ruby-ext (~> 0.8.0)
csso-rails (~> 0.3.4)
minitest minitest
opal opal-rspec (~> 0.4.2)
opal-browser parslet!
opal-sprockets poltergeist (~> 1.5.0)
poltergeist rspec (~> 3.2.0)
rspec salama!
rubyx (= 0.6)! salama-arm!
rx-file! salama-object-file!
sass salama-reader!
selenium-webdriver selenium-webdriver (~> 2.43.0)
susy (= 2.2.5)
thin (~> 1.6.0)
uglifier (>= 2.4.0)
volt (= 0.9.5.pre4)
volt-mongo (~> 0.1.0)
BUNDLED WITH BUNDLED WITH
1.17.2 1.10.5

127
README.md
View File

@ -1,117 +1,36 @@
# Debugger # Debugger
After some tryouts it ended up being an Opal application. That is ruby as javascript in the browser. After some tryouts it ended up being an Opal application. That is ruby as javascript in the browser.
Below is a screenshot.
![Debugger](https://raw.githubusercontent.com/rubyx/rubyx-debugger/master/static/debugger.png) ![Debugger](https://raw.githubusercontent.com/salama/salama-debugger/master/static/debugger.png)
## Views - On the left are the classes of the system. Next idea is to have hover info about them.
- Next a source code view (not implemented)
- next a view of the Virtual Instructions
- last section, current block with current Register Instruction highlighted
- step (next) button for single stepping
- status: starting , running , exited
- bottom row are the registers. If the register hold an object the variables are shown.
(also should have hover info) , the first letter indicates the class, the number is the address
From left to right there are several views showing different data and controls. So lots to do, but a good start.
All of the green boxes are in fact pop-up menus and can show more information.
Most of these are implemented as a single class with the name reflecting what part.
I wrote 2 base classes that handle element generation (ie there is hardly any html involved, just elements)
### Switch view
Top left at the top is a little control to switch files.
The files need to be in the repository, but at least one can have several and switch between
them without stopping the debugger.
Parsing is the only thing that opal chokes on, so the files are parsed by a server script and the
ast is sent to the browser.
### Classes View
The first column on the left is a list of classes in the system. Like on all boxes one can hover
over a name to look at the class and it's instance variables (recursively)
### Source View
Next is a view of the Soml source. The Source is reconstructed from the ast as html. I don't want to use gdb anymore, and it would be easier without using the qemu setup, so:
Soml (Salama object machine language) is is a statically typed language,
maybe in spirit close to c++ (without the c). In the future Salama will compile ruby to soml.
While stepping through the code, those parts of the code that are active get highlighted in blue. - single step debugging of the register machine level (as close to arm as need be)
- visual transitions for steps
Currently stepping is done only in register instructions, which means that depending on the source - visualisation of data in registers (some kind of link to the object)
constructs it may take many steps for the cursor to move on. - show the current instruction and a few around
- show vm object (message etc)
Each step will show progress on the register level though (next view) - show effect of register transitions on vm objects
- visualize vm object content (again some links)
### Register Instruction view # Space
Salama defines a register machine level which is quite close to the arm machine, but with more - Visualise the object space in some way
sensible names. It has 16 registers (below) and an instruction set that is useful for Soml. - Visualise single object, bit like atoms
- values immediate
Data movement related instruction implement an indexed get and set. There is also Constant load and - objects as link
integer operators and off course branches.
Instructions print their name and used registers r0-r15.
The next instruction to be executed is highlighted in blue. A list of previous instructions is shown.
One can follow the effect of instruction in the register view below.
### Status View
The last view at the top right show the status of the machine (interpreter to be precise), the
instruction count and any stdout
Current controls include stepping and three speeds of running the program.
- Next (green button) will execute exactly one instruction when clicked. Mostly useful when
debugging the compiler, ie inspecting the generated code.
- Crawl (first blue button) will execute at a moderate speed. One can still follow the
logic at the register level
- Run (second blue button) runs the program at a higher speed where register instruction just
whizz by, but one can still follow the source view. Mainly used to verify that the source executes
as expected and also to get to a specific place in the program (in the absence of breakpoints)
- Wizz (third blue button) makes the program run so fast that it's only useful function is to
fast forward in the code (while debugging)
### Register view
The bottom part of the screen is taken up by the 16 register. As we execute an object oriented
language, we show the object contents if it is an object (not an integer) in a register.
The (virtual) machine only uses objects, and specifically a linked list of Message objects to
make calls. The current message is always in register 0 (analgous to a stack pointer).
All other registers are scratch for statement use.
In Soml expressions compile to the register that holds the expressions value and statements may use
all registers and may not rely on anything other than the message in register 0.
The Register view is now greatly improved, especially in it's dynamic features:
- when the contents update the register obviously updates
- when the object that the register holds updates, the new value is shown immediately
- hovering over a variable will **expand that variable** .
- the hovering works recursively, so it is possible to drill down into objects for several levels
The last feature of inspecting objects is show in the screenshot. This makes it possible
to very quickly verify the programs behaviour. As it is a pure object system , all data is in
objects, and all objects can be inspected.
### Debugging the debugger
Opal is pre 1.0 and is a wip. While current source map support is quite good, one only gets
real lines when switching debug on. Debug make it load every single file seperately, slooows it
down in other words. Set DEBUG environment to switch it on.
I set the sprockets cache to mem-cache and that increase load time from 12s to 1 , so it's quite
usable and restarting a debug is fine.
## Todos
Breakpoints would be nice at some point. Both in step count and variable value.
## Trying it out
Clone
Bundle
bundle exec rackup

View File

@ -0,0 +1,59 @@
// Place your apps css here
@import "susy";
$susy: (
columns: 24 ,
gutter-position: split ,
);
.debugger-view { @include container(90%); }
.classes {
@include span(3);
}
.one-class {
margin: 10px;
}
.file-view {
@include span(4);
margin: span(1);
}
.source-view { @include span(6); }
.block-view {
@include span(4);
margin-right: span(2);
height: 200px;
}
.status-view {
@include span(2 at 22);
}
.registers-view {
@include span(20 at 3);
}
.register-view {
@include gallery(4);
margin-top: 10px;
}
.field {
@include span(5)
}
.value {
@include span(18)
}
.value-head {
background-color: #C5FFD9;
}
.bright {
background-color: orange ;
}

View File

@ -0,0 +1,59 @@
body {
font-family: arial, helvetica, serif;
}
#nav, #nav ul { /* all lists */
padding: 0;
margin: 0;
list-style: none;
float : left;
width : 10em;
/*border around submenu goes here*/
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
background:#fff;
border:1px solid #C3D46A
}
#nav li { /* all list items */
position : relative;
float : left;
line-height : 1.25em;
width: 9em;
}
#nav li ul { /* second-level lists */
position : absolute;
left: -999em;
margin-left : 10.05em;
margin-top : -1.35em;
}
#nav li ul ul { /* third-and-above-level lists */
left: -999em;
}
#nav li a , li span {
padding-left: 0.5em;
width : 9.5em;
display : block;
color : black;
font-weight : bold;
text-decoration : none;
background-color : white;
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
}
#nav li a:hover {
color : white;
background-color : #F6C739;
}
#nav li:hover ul ul, #nav li:hover ul ul ul {
left: -999em;
}
#nav li:hover ul, #nav li li:hover ul, #nav li li li:hover ul { /* lists nested under hovered list items */
left: auto;
}

View File

@ -0,0 +1,2 @@
# Specify which components you wish to include when
# the "home" component loads.

View File

@ -0,0 +1,10 @@
# Place any code you want to run when the component is included on the client
# or server.
# To include code only on the client use:
# if RUBY_PLATFORM == 'opal'
#
# To include code only on the server, use:
# unless RUBY_PLATFORM == 'opal'
# ^^ this will not send compile in code in the conditional to the client.
# ^^ this include code required in the conditional.

View File

@ -0,0 +1,8 @@
# See https://github.com/voltrb/volt#routes for more info on routes
client '/about', action: 'about'
# The main route, this should be last. It will match any params not
# previously matched.
client '/', {}

View File

@ -0,0 +1,12 @@
module Main
class BlocksController < Volt::ModelController
def initialize *args
super(*args)
blocks = BlocksModel.new
page._blocks = blocks
@volt_app.interpreter.register_event(:instruction_changed, blocks)
end
end
end

View File

@ -0,0 +1,28 @@
module Main
class ClassesController < Volt::ModelController
def initialize *args
super(*args)
page._classes!.clear
all = []
Virtual.machine.space.classes.each do |name , claz|
next if [:Kernel,:Module,:MetaClass,:BinaryCode].index name
all << name
end
all.sort.each do |name|
c = Volt::Model.new :name => name
page._classes << c
end
end
def variables(clas_model)
layout = Virtual.machine.space.get_class_by_name(clas_model._name).object_layout
vars = []
layout.object_instance_names.each do |name|
vars.push name
end
vars
end
end
end

View File

@ -0,0 +1,43 @@
# By default Volt generates this controller for your Main component
require "salama"
require "interpreter/interpreter"
module Main
class MainController < Volt::ModelController
def initialize *args
super(*args)
@volt_app.class.attr_accessor :interpreter
@volt_app.interpreter = Interpreter::Interpreter.new
end
def index
init_machine
end
private
def init_machine
machine = Virtual.machine.boot
code = Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))
Virtual::Compiler.compile( code , machine.space.get_main )
machine.run_before "Register::CallImplementation"
page._interpreter = { }
@volt_app.interpreter.start machine.init
end
# The main template contains a #template binding that shows another
# template. This is the path to that template. It may change based
# on the params._component, params._controller, and params._action values.
def main_path
"#{params._component || 'main'}/#{params._controller || 'main'}/#{params._action || 'index'}"
end
# Determine if the current nav component is the active one by looking
# at the first part of the url against the href attribute.
def active_tab?
url.path.split('/')[1] == attrs.href.split('/')[1]
end
end
end

View File

@ -0,0 +1,55 @@
if RUBY_PLATFORM == 'opal'
require "native"
end
module Main
class ObjectsController < Volt::ModelController
def index_ready
container = Native(self.container).querySelector("ul")
all = container.querySelectorAll("a")
len = all.length - 1
while len >= 0
puts "li #{len}" + all.item(len).innerHTML + " lo"
len = len - 1
end
# red = -> (event) { container.style.backgroundColor = "red" }
red = -> (event) { puts container.innerHTML }
container.addEventListener("mouseenter" , red)
end
def marker id
var = Virtual.machine.objects[id]
if var.is_a? String
str "Wo"
else
str = var.class.name.split("::").last[0,2]
end
str + " : #{id.to_s}"
end
def class_header(id)
object = Virtual.machine.objects[id]
return "" unless object
clazz = object.class.name.split("::").last
"#{clazz}:#{id}"
end
def content(id)
object = Virtual.machine.objects[id]
fields = []
if object and ! object.is_a?(String)
object.get_instance_variables.each do |variable|
f = object.get_instance_variable(variable)
fields << ["#{variable} : #{marker(f.object_id)}" , f.object_id]
end
end
fields
end
def is_object?( id )
Virtual.machine.objects[id] != nil
end
end
end

View File

@ -0,0 +1,26 @@
module Main
class RegistersController < Volt::ModelController
def initialize *args
super(*args)
self.model = []
init_registers
end
def init_registers
@volt_app.interpreter.registers.each do |reg , val|
r = RegisterModel.new( :name => reg , :value => val)
self.model << r
@volt_app.interpreter.register_event(:register_changed, r)
@volt_app.interpreter.register_event(:object_changed, r)
r.register_changed( reg , nil , @volt_app.interpreter.registers[reg])
end
end
def is_object?( id )
Virtual.machine.objects[id] != nil
end
end
end

View File

@ -0,0 +1,12 @@
module Main
class SourcesController < Volt::ModelController
def initialize *args
super(*args)
sources = SourceModel.new
page._sources = sources
@volt_app.interpreter.register_event(:instruction_changed, sources)
end
end
end

View File

@ -0,0 +1,31 @@
module Main
class StatusController < Volt::ModelController
def initialize *args
super(*args)
self.model = Volt::Model.new
update_interpreter
end
def tick
@volt_app.interpreter.tick
update_interpreter
end
def update_interpreter
self._clock = @volt_app.interpreter.clock
self._state = @volt_app.interpreter.state
self._stdout = @volt_app.interpreter.stdout
self._link = @volt_app.interpreter.link.to_s
page._method_name = method_name
page._block_name = @volt_app.interpreter.block ? @volt_app.interpreter.block.name : " "
end
def method_name
bl = @volt_app.interpreter.block
return " " unless bl
return bl.method if bl.method.is_a? String
"#{bl.method.for_class.name}.#{bl.method.name}"
end
end
end

View File

@ -0,0 +1,10 @@
class BlocksModel < Volt::ArrayModel
def instruction_changed old , ins
self.last._class_name = "inactive" if( self.length > 0)
self << { :name => ins.to_s , :class_name => "bright" }
#puts "block #{self.length}"
self.delete_at(0) if( self.length > 5)
end
end

View File

@ -0,0 +1,36 @@
class RegisterModel < Volt::Model
field :name
field :value
field :fields
def register_changed reg , old , value
reg = reg.symbol unless reg.is_a? Symbol
return unless reg == name
self.value = value
calc_fields
end
def object_changed reg
reg = reg.symbol unless reg.is_a? Symbol
return unless reg == name
#puts "Object changed in #{reg}"
calc_fields
end
def calc_fields
#puts "My id #{objects_id} , #{objects_id.class}"
object = Virtual.machine.objects[value]
self.fields.clear
if object and ! object.is_a?(String)
clazz = object.class.name.split("::").last
#puts "found #{clazz}"
self.fields << "#{clazz}:#{object.internal_object_length}"
self.fields << object.get_layout
object.get_instance_variables.each do |variable|
f = object.get_instance_variable(variable)
self.fields << f
end
end
end
end

View File

@ -0,0 +1,23 @@
class SourceModel < Volt::ArrayModel
def instruction_changed old , ins
return unless ins
source = source_text ins.source
if( self.length > 0)
return if self.last._name == source
self.last._class_name = "inactive"
end
self << { :name => source.to_s , :class_name => "bright" }
#puts "sources #{self.length}"
self.delete_at(0) if( self.length > 5)
end
def source_text source
if source.is_a? Virtual::Instruction
return source.class.name
else
return "Method: #{source.name}"
end
end
end

View File

@ -0,0 +1,11 @@
require "salama-reader"
class ParseTask < Volt::Task
def parse(num)
string_input = '"Hello again".putstring()'
parser = Parser::Salama.new
out = parser.parse(string_input)
parts = Parser::Transform.new.apply(out)
parts.to_basic
end
end

View File

@ -0,0 +1,17 @@
<:Title>
blocks index
<:Body>
<div class="block-view">
<div>
<h4> {{page._method_name}} </h4>
<h4> Block: {{page._block_name}} </h4>
</div>
{{ page._blocks.each do |b| }}
<div>
<span class="{{b._class_name}}">
{{b._name}}
</span>
</div>
{{ end }}
</div>

View File

@ -0,0 +1,23 @@
<:Title>
classes index
<:Body>
<div class="classes">
<h4> Classes </h4>
<ul id="nav">
{{page._classes.each do |clas| }}
<li>
<a href="#">{{ clas._name }}</a>
{{ unless variables(clas).empty? }}
<ul>
{{variables(clas).each do |var| }}
<li>
<a href="#">{{var}}</a>
</li>
{{ end }}
</ul>
{{ end }}
</li>
{{end}}
</ul>
</div>

View File

@ -0,0 +1,16 @@
<:Title>
Home
<:Body>
<:classes />
<div class="file-view">
</div>
<:sources />
<:blocks />
<:status/>
<:registers/>

View File

@ -0,0 +1,12 @@
<:Title>
{{ view main_path, "title", {controller_group: 'main'} }}
<:Body>
<div class="debugger_view">
<:volt:notices />
{{ view main_path, 'body', {controller_group: 'main'} }}
</div>

View File

@ -0,0 +1,15 @@
<:Title>
objects index
<:Body>
<ul sid={{attrs.id}}>
<li>
<span>{{class_header(attrs.id)}}</span>
</li>
<li>&nbsp;&nbsp;-------------------------</li>
{{content(attrs.id).each do |con3| }}
<li>
<a href="#">{{con3[0]}}</a>
</li>
{{end}}
</ul>

View File

@ -0,0 +1,19 @@
<:Title>
registers index
<:Body>
<div class="registers-view">
{{ model.each do |reg| }}
<div class="register-view" id="nav">
{{ if(is_object?(reg.value) ) }}
<:objects id={{reg.value}} />
{{else}}
<ul>
<li>
<a href="#">{{reg.value}}</a>
</li>
</ul>
{{ end }}
</div>
{{end}}
</div>

View File

@ -0,0 +1,14 @@
<:Title>
sources index
<:Body>
<div class="source-view">
<h4> Virtual Machine Instruction </h4>
{{page._sources.each do |source| }}
<div>
<span class="{{source._class_name}}">
{{source._name}}
</span>
</div>
{{end}}
</div>

View File

@ -0,0 +1,17 @@
<:Title>
status index
<:Body>
<div class="status-view">
<h4> Interpreter </h4>
Instruction {{ _clock}}
<button e-click="tick"> Next </button>
<br/>
<span> State </span>
<span> {{_state}} </span>
<br/>
<span> Link: {{_link}} </span>
<br/>
Stdout <br/>
<span> {{_stdout}} </span>
</div>

View File

@ -1,98 +0,0 @@
body
background-color: #1a1a1a
color: white
.one_class, .classes, .vool_view ,.mom_view , .risc_view, .status_view ,.vool_view
position: relative
float: left
.mom_view , .risc_view , .status_view , .registers_view, .register_view
position: relative
float: left
.one_class
margin: 10px
.classes
width: 16%
margin-left: 1%
.vool_view
width: 12%
margin-left: 1%
.mom_view
width: 16%
margin-left: 1%
overflow-x: hidden
.risc_view
width: 34%
margin-left: 1%
overflow-x: hidden
.status_view
width: 14%
margin-left: 1%
line-height : 1.25em
.header_state
color: #53a5ff
.labels_view
width: 18%
margin-right: 2%
height: 200px
.registers_view
width: 79%
margin-left: 1%
.register_view
width: 19%
margin-right: 1%
margin-top: 10px
&:nth-child(5n + 1)
clear: left
.field
width: 80%
.value
width: 80%
.value_head
background-color: #C5FFD9
.statement
margin-left: 10px
.ticker
text-align: right
.next , .run , .wizz
border-radius: 7px
font-size: 1em
.next
background-color: #00FF66
.run
background-color: #00CC33
.wizz
background-color: #009900
.risc_bright , .mom_bright
background-color: black
color: #53a5ff
border-radius: 7px
.fade_in
transition: background-color 100ms linear
padding-right: 6px
padding-left: 6px
background-color: #00E3FF
border-radius: 7px
h4.select
z-index: 20

View File

@ -1,45 +0,0 @@
body
font-family: arial, helvetica, serif
#nav , #nav ul
padding: 0
margin: 0
list-style: none
float: left
width: 100%
border-radius: 8px
background: black
border: 2px solid #C3D46A
#nav
li
position: relative
float: left
line-height: 1.25em
width: 99%
a , span
width: 99%
display: block
text-decoration: none
background-color: black
border-radius: 7px
ul
position: absolute
left: -999em
margin-left: 99%
margin-top: -2.7em
ul
left: -999em
#nav li a:hover
color: white
background-color: #98CC1F
#nav li:hover ul ul, #nav li:hover ul ul ul , #nav li:hover ul ul ul ul , #nav li:hover ul ul ul ul ul
left: -999em
/* lists nested under hovered list items */
#nav li:hover ul, #nav li li:hover ul, #nav li li li:hover ul, #nav li li li li:hover ul , #nav li li li li li:hover ul
left: auto

View File

@ -1,5 +0,0 @@
class Object
int main()
return 55.puti()
end
end

View File

@ -1,22 +0,0 @@
class Object
int fibonaccir( int n )
if_plus( n - 1 )
int tmp
tmp = n - 1
int a = fibonaccir( tmp )
tmp = n - 2
int b = fibonaccir( tmp )
return a + b
else
return n
end
end
int fib_print(int n)
int fib = fibonaccir( n )
fib.putint()
return fib
end
int main()
return fib_print(7)
end
end

View File

@ -1,20 +0,0 @@
class Object
int fibonaccit(int n)
int a = 0
int b = 1
n = n - 1
while_plus( n )
int tmp = a
a = b
b = tmp + b
n = n - 1
end
b.putint()
return b
end
int main()
int f = fibonaccit( 10 )
return f.puti()
end
end

View File

@ -1,6 +0,0 @@
class Object
int main()
"Hello World".putstring()
return 1
end
end

View File

@ -1,13 +0,0 @@
class Object
int itest(int n)
if_zero( n - 12)
"then".putstring()
else
"else".putstring()
end
end
int main()
itest(20)
end
end

View File

@ -1,10 +0,0 @@
class Object
int main()
int n = 14
if_plus( n - 12)
"then".putstring()
else
"else".putstring()
end
end
end

View File

@ -1,23 +0,0 @@
class Layout < Object
Class object_class()
return get_internal_word(2)
end
end
class Object
Layout get_layout()
return get_internal_word(1)
end
Class get_class()
Layout l = get_layout()
return l.object_class()
end
int main()
return get_class()
end
end

View File

@ -1,8 +0,0 @@
class Object
int puts(Word str)
return str
end
int main()
puts("Hello")
end
end

View File

@ -1,23 +0,0 @@
class Object
int times(int a, int b)
if_zero( b )
a = 0
else
int m = b - 1
int t = times(a, m)
a = a + t
end
return a
end
int t_seven()
int tim = times(5,3)
tim.putint()
return tim
end
int main()
return t_seven()
end
end

View File

@ -1,12 +0,0 @@
class Object
int main()
int i = 5
while_plus(i)
"out ".putstring()
i = i - 1
end
return i
end
end

View File

@ -1,16 +1,4 @@
require 'bundler' # Run via rack server
Bundler.require require 'bundler/setup'
require 'tilt/erb' require 'volt/server'
require "opal" run Volt::Server.new.app
require 'opal-sprockets'
Opal.use_gem("rubyx")
run Opal::Sprockets::Server.new { |s|
s.main = 'debugger.js.rb'
s.append_path 'lib'
s.append_path 'assets'
s.debug = !ENV["DEBUG"].nil?
s.index_path = "index.html.erb"
s.sprockets.cache = Sprockets::Cache::MemoryStore.new(50000)
}

136
config/app.rb Normal file
View File

@ -0,0 +1,136 @@
# app.rb is used to configure your app. This code is only run on the server,
# then any config options in config.public are passed to the client as well.
#hint_path = Bundler.definition.specs["simptip"].first.full_gem_path
#ENV["SASS_PATH"] = ENV["SASS_PATH"] + File::PATH_SEPARATOR + hint_path
Volt.configure do |config|
# Setup your global app config here.
#######################################
# Basic App Info (stuff you should set)
#######################################
config.domain = 'salama-debugger.com'
config.app_name = 'Salama-debugger'
config.mailer.from = 'Salama-debugger <no-reply@salama-debugger.com>'
############
# App Secret
############
# Your app secret is used for signing things like the user cookie so it can't
# be tampered with. A random value is generated on new projects that will work
# without the need to customize. Make sure this value doesn't leave your server.
#
# For added security we recommend moving the app secret into an environment. You can
# setup that like so:
#
# config.app_secret = ENV['APP_SECRET']
#
config.app_secret = 'qwSEmWdixdHgwOgXiLdGJt87b9TxMq009gbJWn0fOTygfIk6fAIlgHO9tAPbA4vaKgY'
###############
# Log Filtering
###############
# Data updates from the client come in via Tasks. The task dispatcher logs all calls to tasks.
# By default hashes in the arguments can be filtered based on keys. So any hash with a key of
# password will be filtered. You can add more fields to filter below:
config.filter_keys = [:password]
##########
# Database
##########
# Database config all start with db_ and can be set either in the config
# file or with an environment variable (DB_NAME for example).
# config.db_driver = 'mongo'
# config.db_name = (config.app_name + '_' + Volt.env.to_s)
# config.db_host = 'localhost'
# config.db_port = 27017
#####################
# Compression options
#####################
# If you are not running behind something like nginx in production, you can
# have rack deflate all files.
# config.deflate = true
#######################
# Public configurations
#######################
# Anything under config.public will be sent to the client as well as the server,
# so be sure no private data ends up under public
# Use username instead of email as the login
# config.public.auth.use_username = true
#####################
# Compression Options
#####################
# Disable or enable css/js compression. Default is to only run in production.
# if Volt.env.production?
# config.compress_javascript = true
# config.compress_css = true
# end
################
# Mailer options
################
# The volt-mailer gem uses pony (https://github.com/benprew/pony) to deliver e-mail. Any
# options you would pass to pony can be setup below.
# NOTE: The from address is setup at the top
# Normally pony uses /usr/sbin/sendmail if one is installed. You can specify smtp below:
# config.mailer.via = :smtp
# config.mailer.via_options = {
# :address => 'smtp.yourserver.com',
# :port => '25',
# :user_name => 'user',
# :password => 'password',
# :authentication => :plain, # :plain, :login, :cram_md5, no auth by default
# :domain => "localhost.localdomain" # the HELO domain provided by the client to the server
# }
#############
# Message Bus
#############
# Volt provides a "Message Bus" out of the box. The message bus provides
# a pub/sub service between any volt instance (server, client, runner, etc..)
# that share the same database. The message bus can be used by app code. It
# is also used internally to push data to any listening clients.
#
# The default message bus (called "peer_to_peer") uses the database to sync
# socket ip's/ports.
# config.message_bus.bus_name = 'peer_to_peer'
#
# Encrypt message bus - messages on the message bus are encrypted by default
# using rbnacl.
# config.message_bus.disable_encryption = true
#
# ## MessageBus Server -- the message bus binds to a port and ip which the
# other volt instances need to be able to connect to. You can customize
# the server below:
#
# Port range - you can specify a range of ports that an instance can bind the
# message bus on. You can specify a range, an array of Integers, or an array
# of ranges.
# config.message_bus.bind_port_ranges = (58000..61000)
#
# Bind Ip - specifies the ip address the message bus server should bind on.
# config.message_bus.bind_ip = '127.0.0.1'
#############
# Concurrency
#############
# Volt provides a thread worker pool for incoming task requests (and all
# database requests, since those use tasks to do their work.) The following
# lets you control the size of the worker pool. Threads are only created as
# needed, and are removed after a certain amount of inactivity.
# config.min_worker_threads = 1
# config.max_worker_threads = 10
#
# You can also specify the amount of time a Task should run for before it
# timeout's. Setting this to short can cause unexpected results, currently
# we recomend it be at least 10 seconds.
# config.worker_timeout = 60
end

15
config/base/index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<%# IMPORTANT: Please read before changing! %>
<%# This file is rendered on the server using ERB, so it does NOT use Volt's %>
<%# normal template system. You can add to it, but keep in mind the template %>
<%# language difference. This file handles auto-loading all JS/Opal and CSS. %>
<head>
<meta charset="UTF-8" />
<%= javascript_tags %>
<%= css_tags %>
</head>
<body>
</body>
</html>

6
config/dependencies.rb Normal file
View File

@ -0,0 +1,6 @@
# Specify which components you wish to include when
# the "home" component loads.
Opal.use_gem("salama-reader")
Opal.use_gem("salama-object-file")

View File

@ -0,0 +1,10 @@
# Place any code you want to run when the component is included on the client
# or server.
# To include code only on the client use:
# if RUBY_PLATFORM == 'opal'
#
# To include code only on the server, use:
# unless RUBY_PLATFORM == 'opal'
# ^^ this will not send compile in code in the conditional to the client.
# ^^ this include code required in the conditional.

View File

@ -0,0 +1,2 @@
Opal.use_gem "salama"
Opal.use_gem "salama-arm"

7
config/routes.rb Normal file
View File

@ -0,0 +1,7 @@
# See https://github.com/voltrb/volt#routes for more info on routes
client '/about', action: 'about'
# The main route, this should be last. It will match any params not
# previously matched.
client '/', {}

View File

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Debugger</title>
<meta charset="utf-8"/>
<link rel="stylesheet" href="/assets/css/menu.css" type="text/css" charset="utf-8">
<link rel="stylesheet" href="/assets/css/app.css" type="text/css" charset="utf-8">
</head>
<body>
<%= javascript_include_tag "debugger" %>
</body>
</html>

View File

@ -1,19 +0,0 @@
require_relative "element_view"
# A very simple ElementView with constant text and class. It uses the ElementView.div function
# to generate the html, see there for details
#
class ConstantView < ElementView
# store the class and text
def initialize class_or_id , text = nil
@class_or_id = class_or_id
@text = text
end
# use ElementView.div to create html from the class and text
def draw
@element = div(@class_or_id , @text)
end
end

View File

@ -1,90 +0,0 @@
# The basic idea is somewhat that of a shadow dom.
#
# ElementView wraps a single div with whatever content you want (derive to implement the view)
#
# It must have an element, which is drawn. Draw returns the div or whatever. An ElementView
# does not draw itself, but rather is drawn.
#
# Listviews provide structure
#
class ElementView
def initialize
@element = nil
end
#abstract function that should return the single element that is being represented
# the element is also stored in @element
def draw
raise "implement me to return an Element"
end
# helper function to create an element with possible classes, id and text
# The first argument is a bit haml inspired, so "tagname.classname" is the format
# but if tagname is ommited it will default to div
# also several classnames may be given
# if one of the names ends in a ! (bang) it will be assigned as the id
# second argument is optional, but if given will be added as text (content) to the newly
# created Element
# return the new Element, which is not linked into the dom at that point (see << and add*)
def div(name_class = "div" , text = nil)
name , clazz = name_class.split(".")
name = "div" if name.empty?
element = $document.create_element(name)
element.text = text if text
return element unless clazz
if( clazz.is_a? Array )
clazz.each { |c| add_class_or_id( element , cl )}
else
add_class_or_id element , clazz
end
element
end
def add_class_or_id element , class_or_id
return element unless class_or_id
if class_or_id[-1] == "!"
element.id = class_or_id[0 ... -1]
else
element.add_class class_or_id
end
element
end
# wrap the @element variable with the given element
# so if wrapper == <h4/> the new @element will be <h4> old @element </h4>
# return the new @element, which is wrapper
def wrap_element wrapper
@element = wrap_node_with @element , wrapper
end
# wrap the given node with the wappper, so for a div wrapper and a button node
# the result will be <div> <button>whatever was in there</button> <div>
def wrap_node_with node , wrapper
node.replace_with(wrapper) if node.parent
wrapper << node
end
# add the given element to the @element, at the end
# return the div that was passed in (use << to return the @element)
def append_element div
@element << div
div
end
# add the given element to the @element , at the front
# return the div that was passed in (use >> to return the @element)
def prepend_element div
@element >> div
div
end
# create a new element with class and possibly text
# add that new element to the @element
# return the newly created element
def add class_or_id , tex = nil
append_element div( class_or_id , tex)
end
end

View File

@ -1,74 +0,0 @@
require_relative "element_view"
# Listviews hold an array of elements and are responsible for drawing (and re-drawing them)
#
# A ListView hold the elements, but also the drawn html divs. You can change the element
# structure by adding/removing/replacing and the ListView will take care of redrawing the html
#
# A ListView is itself an ElementView so one can build recursive structures.
#
# Also one can easily change the root html element, or by deriving wrap or edit the resulting html
#
class ListView < ElementView
def initialize children
@children = children
@elements = []
end
def length
@children.length
end
# create a root node acording to the tag given (default div)
# The tag name will be passed to the div function, so class and id may be set as well (see there)
# draw all children and keep the elements as @elements
# return (as per base class) the single root of the collection
def draw root = "div"
@element = div(root)
@elements = @children.collect do | c |
append_element c.draw
end
@element
end
# replace the child at index with the given one (second arg)
# The child must be an ElementView , which will be rendered and
# the old node will be replaced in the live dom
def replace_at( index , node)
old = @elements[index]
@children[index] = node
rendered = node.draw
@elements[index] = rendered
old.replace_with(rendered) if old
end
# remove the first child and element (from view)
def remove_first
remove_at 0
end
# remove both child and element at given position
def remove_at index
raise "index out of bounds #{index} => #{@children.length}" if(index >= @children.length or index < 0)
@children.delete_at( index )
element = @elements.delete_at(index)
element.remove if element
end
# remove all elements and views, basically resetting the list to empty
def clear_view
remove_first while( ! @children.empty? )
end
# append a View instnace to the children array
# render it and append it to the html element
# and keep a copy in @elements
def append_view view
@children << view
rendered = view.draw
@elements << rendered # add to internal array
@element << rendered # add to html children
rendered
end
end

View File

@ -1,62 +0,0 @@
require "opal"
require "opal-parser"
require 'opal/compiler'
require 'browser'
require 'browser/http'
require 'native'
require "rubyx"
require "ast"
require "util/eventable"
require "risc/interpreter"
# the base, our own mini framework, allows for child and parent views and handles updates
require "base/list_view"
# each seperate view is in it's own class.
require "views/left_view"
require "views/status_view"
require "views/vool_view"
require "views/mom_view"
require "views/risc_view"
require "views/registers_view"
class Bignum
end
class String
def codepoints
arr = []
one = nil
self.each_byte do |c|
if( one )
arr << (one + c * 256)
one = nil
else
one = c
end
end
arr
end
end
module RubyX
def self.debugger_options
{ parfait: {factory: 50} }
end
end
class MainView < ListView
def initialize
compiler = RubyX::RubyXCompiler.new(RubyX.debugger_options)
input = "class Space;def main(arg); return 1; end; end"
linker = compiler.ruby_to_binary(input , :interpreter)
@interpreter = Risc::Interpreter.new(linker)
super( [LeftView.new(@interpreter) ,
VoolView.new(@interpreter) ,
MomView.new(@interpreter) ,
RiscView.new(@interpreter) ,
StatusView.new(@interpreter) ,
RegistersView.new(@interpreter) ] )
end
end
view = MainView.new()
view.draw.append_to($document.body)

View File

@ -1,44 +0,0 @@
require_relative "ref_view"
class ClassesView < ListView
def initialize interpreter
@interpreter = interpreter
@interpreter.register_event(:state_changed, self)
super( class_views )
end
def class_views
classes = []
Parfait.object_space.classes.each do |name , claz|
classes << claz
end
classes.sort! {|a,b| a.name <=> b.name }
classes.collect{|c| ClassView.new(c)}
end
def state_changed old , new_s
return unless new_s == :running
class_views.each_with_index do |v, i|
replace_at i , v
end
end
def draw
super()
wrap_element div("ul.nav!")
wrap_element( div("h4" , "Classes") )
return @element
end
end
class ClassView < RefView
def initialize clazz
super(clazz.name , clazz , 20 )
end
def ref_text
@name
end
end

View File

@ -1,120 +0,0 @@
class HtmlConverter < AST::Processor
alias :old_process :process
def process s
return "" unless s
#puts s.type
old_process(s)
end
def handler_missing s
puts "Missing: " + s.type
"Missing #{s.type}"
end
def div( statement , html)
"<div class='statement' id='i#{statement.object_id.to_s(16)}'>" + html + "</div>"
end
def span( statement , html)
"<span class='expression' id='i#{statement.object_id.to_s(16)}'>" + html + "</span>"
end
def on_function( statement)
return_type , name , parameters, kids , receiver = *statement
str = return_type + " "
str += receiver + "." if receiver
str += name.to_a.first + "("
str += process(parameters) + ")<br>"
str += process(kids) + "end<br>"
div(statement,str)
end
def on_parameters statement
process_all(statement.children).join(",")
end
def on_parameter p
type , name = *p
span(type,type) + " " + span(name,name)
end
def on_string s
span(s, "'" + s.first + "'")
end
def on_receiver expression
span expression , process(expression.first)
end
def on_field expression
span expression , process(expression.first)
end
def on_field_access statement
receiver_ast , field_ast = *statement
receiver = process(receiver_ast)
field = process(field_ast)
span( statement , receiver + "." + field)
end
def on_field_def statement
type , name , value = *statement
str = span(type, type) + " " + process(name)
str += " = #{process(value)}" if value
div(statement,str)
end
def on_return statement
str = "return " + process(statement.first )
div(statement,str)
end
def on_false_statements s
on_statements s
end
def on_true_statements s
on_statements s
end
def on_statements s
str = ""
s.children.each do |c|
str += process(c).to_s
end
div(s,str)
end
def on_while_statement statement
branch_type , condition , statements = *statement
condition = condition.first
ret = "while_#{branch_type}(" + process(condition) + ")<br>"
ret += process(statements)
ret += "end"
div(statement,ret)
end
def on_if_statement statement
branch_type , condition , if_true , if_false = *statement
condition = condition.first
ret = "if_#{branch_type}(" + process(condition) + ")<br>" + process(if_true)
ret += "else" + "<br>" + process(if_false) if if_false
ret += "end"
div(statement,ret)
end
def on_assignment statement
name , value = *statement
name = process(name)
v = process(value)
str = name + " = " + v
div(statement,str)
end
def on_call c
name , arguments , receiver = *c
ret = process(name)
ret = process(receiver.first) + "." + ret if receiver
ret += "("
ret += process(arguments).join(",")
ret += ")"
span(c,ret)
end
def on_operator_value statement
operator , left_e , right_e = *statement
left_reg = process(left_e)
right_reg = process(right_e)
span(statement , left_reg + " " + operator + " " + right_reg )
end
def on_arguments args
args.children.collect{|c| process(c)}
end
def on_name name
span(name,name.first)
end
def on_int i
span(i , i.first.to_s)
end
end

View File

@ -1,89 +0,0 @@
require_relative "classes_view"
# the whole of the left, ie selection, space and classes
class LeftView < ListView
def initialize( interpreter )
@interpreter = interpreter
super([ SelectView.new(interpreter) ,
ObjectView.new( Parfait.object_space , @interpreter , 26),
ClassesView.new(interpreter) ])
interpreter.register_event(:state_changed, self)
end
# need to re-init when we go to running, as the objects (and the actual space) change
# we replace space and class view with new instances
def state_changed( old , new_s )
return unless new_s == :running
space = ObjectView.new( Parfait.object_space , @interpreter , 26)
replace_at( 1 , space )
replace_at( 2 , ClassesView.new(@interpreter) )
end
def draw
super(".classes")
end
end
# view for the little code select, implemented as a normal expandable menu
#
# on click calls select method
#
# derive from element, meaning we draw
# # TODO: make into listview, so code can be the next level expansion
class SelectView < ElementView
def initialize( interpreter )
super
@interpreter = interpreter
@codes = nil
end
def draw
@element = div("h4.select", "Code") << (list = div("ul.nav!"))
list << (div("li.code_list") << div("a.selected" , "none selected"))
selection_codes unless @codes
@element << div("br")
@element << div("br")
end
def selection_codes
@codes = get_codes.keys
list = div "ul"
@codes.each do |c|
code = div("li") << div("a" , c )
code.style["z-index"] = 10
code.on("click"){ select(c) }
list << code
end
@element.at_css(".code_list") << list
end
# select method set up as click handler for the codes
# restart the interpreter after compiling
def select( code )
puts "selecting #{code}"
@interpreter.set_state :stopped
@element.at_css(".selected").text = code
ruby = as_main(get_codes[code])
compiler = RubyX::RubyXCompiler.new(RubyX.debugger_options)
linker = compiler.ruby_to_binary(ruby, :interpreter)
@interpreter.start_program(linker)
end
def as_main(statements)
"class Space ;def yielder; return yield ; end;def main(arg) ; #{statements}; end; end"
end
def get_codes
{ while_with_calls: 'a = 2; while( 0 < a); a = a - 1;end;return a',
set_internal_byte: "return 'Hello'.set_internal_byte(1,75)" ,
basic_if: 'if( 10 ); return "then";else;return "else";end' ,
plus: 'return 5 + 7' ,
yield: "a = yielder {return 15} ; return a" ,
return: 'return 5' ,
hello_world: "h = 'Hello World'.putstring;return h",
dynamic_call: "a = 150 ; return a.div10",
}
end
end

View File

@ -1,43 +0,0 @@
require "base/constant_view"
require "base/list_view"
class MomView < ListView
def initialize interpreter
@interpreter = interpreter
@current = nil
super([start_view])
@interpreter.register_event(:instruction_changed, self)
@interpreter.register_event(:state_changed, self)
end
def start_view
ConstantView.new( "span.mom_bright" , "starting" )
end
def instruction_changed
i = @interpreter.instruction
return unless i && i.source.is_a?(Mom::Instruction)
return if i.source == @current
@current = i.source
@element.at_css(".mom_bright").remove_class("mom_bright")
instruction = append_view( ConstantView.new( "span.mom_bright" , @current.to_s ) )
wrap_node_with( instruction , div )
remove_first if( @elements.length > 6)
end
def draw
super()
wrap_node_with @elements.first , div
wrap_element div(".mom_view") << div("h4" ,"Mom::Instruction")
@element
end
def state_changed(old , new_s)
return unless new_s == :running
clear_view
@current = nil
append_view start_view
end
end

View File

@ -1,73 +0,0 @@
require_relative "ref_view"
class ObjectView < ListView
# z is the z-index
def initialize object , interpreter = nil , z = nil
@object = object
@z = z
@interpreter = interpreter
@interpreter.register_event(:object_changed, self) if interpreter
super( content_elements )
end
def draw
@element = super(@interpreter ? "ul.nav!" : "ul")
prepend_element div( "li" ) << div("span" , class_header )
return @element
end
def object_changed( reg , at)
#puts "Object changed in #{reg} , at #{at}"
for_object = @interpreter.get_register( reg )
return unless for_object == @object
#puts "Object changed #{for_object} , at #{at}"
variable = @object.get_instance_variables.get(at)
if(variable)
f = @object.get_instance_variable(variable)
else
variable = at.to_s
f = @object.get_internal_word(at)
end
#puts "got var name #{variable}#{variable.class} for #{at}, #{f}"
view = RefView.new( variable , f , @z )
if( @children[at + 1] )
replace_at(at + 1, view)
else
append_view(view)
end
end
def class_header
str = Risc::Position.set?(@object).to_s
clazz = @object.class.name.split("::").last
[clazz, str].join " : "
end
def content_elements
fields = [ConstantView.new("li" , "------------------------------")]
object = @object
if object and ! object.is_a?(String)
object.get_instance_variables.each do |variable|
f = object.get_instance_variable(variable)
fields << RefView.new( variable , f , @z )
end
if( object.is_a?(Parfait::List) )
index = 0
object.each do | o|
fields << RefView.new( index.to_s , o , @z )
index += 1
end
end
if( object.is_a?(Parfait::Integer) )
fields << RefView.new( 3.to_s , object.value , @z )
end
if( object.is_a?(Parfait::Word) )
fields << RefView.new( 3.to_s , object.to_string , @z )
end
end
fields
end
end

View File

@ -1,69 +0,0 @@
class RefView < ListView
def initialize name , value , z = nil
@name = name
@value = value
@z = z
super []
end
attr_reader :value
def value= val
@value = val
add_hover
end
def draw
@element = div("li") << div("a" , ref_text )
add_hover
@element.style["z-index"] = @z if @z
@element
end
def ref_text
"#{@name} : #{marker()}"
end
def add_hover
return if is_string?
@element.on("hover"){ hover } if is_object?(@value)
end
def is_object?( )
return false if @value.is_a?(Fixnum)
return false unless @value
! is_label?
end
def is_string?()
@value.is_a? String
end
def is_label?
@value.is_a?(Risc::Label)
end
def is_nil?()
@value.nil?
end
def hover
#puts "hovering #{@name}"
append_view ObjectView.new(@value)
@element.off("hover")
end
def marker
if is_string?
str = @value
elsif is_object?
str = Risc::Position.get(@value).to_s
elsif is_label?
str = "Label"
else
str = @value.to_s
end
end
end

View File

@ -1,54 +0,0 @@
require_relative "object_view"
class RegistersView < ListView
def initialize interpreter
@interpreter = interpreter
@interpreter.register_event(:register_changed, self)
kids = []
@interpreter.registers.each do |reg , val|
kids << ValueView.new( val )
end
super(kids)
end
def draw
super( "div.registers_view" )
@element.children.each_with_index do |reg, index|
elem = div("div.register_view")
wrap_node_with reg , elem
end
@element
end
def register_changed( reg , old , value )
reg = reg.symbol unless reg.is_a? Symbol
index = reg.to_s[1 .. -1 ].to_i
has = Risc::Position.set?(value)
if( has )
if has.object.is_a?(Risc::Label)
swap = ValueView.new "Label: #{has.object.name}"
else
swap = ObjectView.new( value , @interpreter , 16 - index )
end
else
swap = ValueView.new value
end
replace_at index , swap
# @elements[index].style["z-index"] = -index
end
end
class ValueView < ElementView
def initialize value
@value = value
end
def draw
li = div("li")
li << div("span", @value)
@element = div("ul.nav!") << li
end
end

View File

@ -1,42 +0,0 @@
require "base/constant_view"
require "base/list_view"
class RiscView < ListView
def initialize interpreter
@interpreter = interpreter
super([start_view])
@interpreter.register_event(:instruction_changed, self)
@interpreter.register_event(:state_changed, self)
end
def start_view
ConstantView.new( "span.risc_bright" , "starting" )
end
def instruction_changed
@element.at_css(".risc_bright").remove_class("risc_bright")
instruction = append_view( ConstantView.new( "span.risc_bright" , instruction_text ) )
wrap_node_with instruction , div
remove_first if( @elements.length > 6)
end
def draw
super()
wrap_node_with @elements.first , div
wrap_element div(".risc_view") << div("h4" ,"Register Machine Instruction")
@element
end
def state_changed old , new_s
return unless new_s == :running
clear_view
append_view start_view
end
def instruction_text
return "" unless @interpreter.instruction
@interpreter.instruction.to_s
end
end

View File

@ -1,85 +0,0 @@
require "browser/delay"
class StatusView < ElementView
def initialize interpreter
@interpreter = interpreter
@running = false
end
def draw
header = div("h4" , "Interpreter" )
header << div("span.header_state" , state_text)
@element = div(".status_view") <<
header <<
div("button.next" , "Next") <<
div("button.run" , "Run") <<
div("button.wizz" , "Wizz") <<
div( "br") <<
div("span.clock" , clock_text) <<
div( "br") <<
div("span.flags" , flags_text) <<
div( "br") <<
div( "span.stdout" , "Stdout") <<
div( "br") <<
div( "span.status" , "Status")
# set up event handler
@element.at_css(".next").on("click") { self.update }
@element.at_css(".run").on("mousedown") { self.start( 0.1 ) }
@element.at_css(".wizz").on("mousedown") { self.start( 0.0 ) }
@element.at_css(".run").on("mouseup") { self.stop }
@element.at_css(".wizz").on("mouseup") { self.stop }
return @element
end
def start(speed)
@running = speed
run
end
def stop
@running = false
end
def run
return unless @running
proc = Proc.new do
self.update
self.run
end
proc.after( @running )
end
def update
@interpreter.tick
@element.at_css(".clock").text = clock_text
@element.at_css(".header_state").text = state_text
@element.at_css(".flags").text = flags_text
@element.at_css(".stdout").text = @interpreter.stdout
@element.at_css(".status").text = status_text
end
def status_text
return unless @interpreter.instruction
return "#{@interpreter.instruction.to_s}" unless @interpreter.instruction.source
source = @interpreter.instruction.source
s = "#{source.to_s}"
if( source.respond_to?(:source) and source.source )
s += @interpreter.instruction.source.source.to_s
end
s
end
def state_text
" (#{@interpreter.state})"
end
def flags_text
flags = []
@interpreter.flags.each do |name,value|
flags << name if value
end
"Flags #{flags.join(':')}"
end
def clock_text
"Instruction #{@interpreter.clock}-0x#{@interpreter.pc.to_s(16)}"
end
end

View File

@ -1,46 +0,0 @@
require_relative "html_converter"
class VoolView < ElementView
def initialize interpreter
@interpreter = interpreter
@interpreter.register_event(:instruction_changed, self)
end
def draw
@text = div(".text")
@ticker = div(".ticker")
@element = div(".vool_view") << div("h4.source" , "Class.Method") << @ticker << @text
@element
end
def instruction_changed
i = @interpreter.instruction
return "" unless i
if i.is_a?(Risc::FunctionReturn)
link = @interpreter.get_register( i.register )
puts "Link #{link}:#{link.class}"
raise "No link method" unless link
end
method = nil
case i.source
when Mom::Instruction
if(i.source.is_a?(Mom::SimpleCall))
method = i.source.method
end
#TODO, give mom a source
when Parfait::Callable
method = i.source
when String
return
else
raise "Unrecognized source #{i.source.class.name} for #{i}"
end
update_method(method) if method
end
def update_method(method)
@text.inner_html = method.name
end
end

View File

@ -0,0 +1,5 @@
require 'spec_helper'
describe '', type: :feature do
# Specs here
end

View File

@ -0,0 +1,5 @@
require 'spec_helper'
describe '', type: :feature do
# Specs here
end

View File

@ -0,0 +1,5 @@
require 'spec_helper'
describe '', type: :feature do
# Specs here
end

View File

@ -0,0 +1,5 @@
require 'spec_helper'
describe '', type: :feature do
# Specs here
end

View File

@ -0,0 +1,5 @@
require 'spec_helper'
describe '', type: :feature do
# Specs here
end

View File

@ -0,0 +1,5 @@
require 'spec_helper'
describe '', type: :feature do
# Specs here
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 KiB

After

Width:  |  Height:  |  Size: 198 KiB