Compare commits
157 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
14297baeeb | ||
|
dbb400ac08 | ||
|
2159c86a5b | ||
|
bba8f787d5 | ||
|
11cdb5872a | ||
|
24961e2e10 | ||
|
3451b546c3 | ||
|
9832c8730b | ||
|
89e221c748 | ||
|
315be69851 | ||
|
e90597c332 | ||
|
c379d0f09f | ||
|
6c597bea69 | ||
|
07edd4ba60 | ||
|
e193d50efd | ||
|
ce0bdc46a9 | ||
|
88e49afb60 | ||
|
ff3990841b | ||
|
0ff418a98c | ||
|
7a8e308665 | ||
|
2e3475e040 | ||
|
4ce6aab51c | ||
|
17a49348db | ||
|
73643e4882 | ||
|
509aff9552 | ||
|
4c342d064d | ||
|
7a9e10fb5f | ||
|
c2d69c767c | ||
|
2feb287b50 | ||
|
0c2738cdef | ||
|
7be8e040bb | ||
|
a6c63f4e57 | ||
|
cc6a050250 | ||
|
0aafeeeb22 | ||
|
ba34c510c3 | ||
|
daa75719cc | ||
|
5aebc464e2 | ||
|
66e989f066 | ||
|
0a67fc38e4 | ||
|
dee9eb4dca | ||
|
7c18ab3e36 | ||
|
10664ef090 | ||
|
3681b4b5d7 | ||
|
0f7fb9e70f | ||
|
6812b7503b | ||
|
1b887c0186 | ||
|
969fa758a1 | ||
|
cad3deab3a | ||
|
453f7d5b4a | ||
|
919b31ed3d | ||
|
30eed9274e | ||
|
cfc5163fb6 | ||
|
9c637243ff | ||
|
9fbf58bf0f | ||
|
7a86f60c2d | ||
|
f7981dcce5 | ||
|
65e5f39420 | ||
|
04c7ab7fee | ||
|
04da6af347 | ||
|
7f6f7ee4fd | ||
|
6bbbef235c | ||
|
ccf3a37003 | ||
|
a167a87b1f | ||
|
d19e89567f | ||
|
752310ab0a | ||
|
f2b14c743d | ||
|
09bfae1a5f | ||
|
feeedf973d | ||
|
88aa296356 | ||
|
e8b0a38478 | ||
|
be76a57fde | ||
|
1fd78bf602 | ||
|
10d21614a9 | ||
|
a18bbeebdf | ||
|
b76fe1645e | ||
|
4bf8ac5345 | ||
|
3477de8c81 | ||
|
18cb04240d | ||
|
a8a233705d | ||
|
17fb7fbf74 | ||
|
922ec10f93 | ||
|
76a698f028 | ||
|
b6bfddf536 | ||
|
9cb4a787b2 | ||
|
8cde7011ef | ||
|
feca6cfbee | ||
|
75b358f2bb | ||
|
88935db881 | ||
|
9fc354d30f | ||
|
91e3a8fc03 | ||
|
b4630fb501 | ||
|
b4fcf6a711 | ||
|
94292bf1ca | ||
|
906017d1eb | ||
|
b8e309b701 | ||
|
4752732bf8 | ||
|
45a2c707da | ||
|
8eade695a4 | ||
|
82b78b8825 | ||
|
37e24cd02a | ||
|
0db8d87c09 | ||
|
b8dd2b257c | ||
|
c87b1f615e | ||
|
e48b7f5c7a | ||
|
ed5b946a70 | ||
|
36e3a8d4cc | ||
|
d23a9846e3 | ||
|
ab55f64cdf | ||
|
3ca4f29ed1 | ||
|
c0bdfe149c | ||
|
5ec7ea6d56 | ||
|
ee788b3507 | ||
|
85e099382d | ||
|
7d214e7013 | ||
|
c5a07be6ac | ||
|
b3de7c9b5e | ||
|
516b041bed | ||
|
a25d292e1f | ||
|
167353fdf3 | ||
|
95c4d656b3 | ||
|
3319b0cd98 | ||
|
7820c5eff0 | ||
|
a56e811699 | ||
|
83e0c8a925 | ||
|
7885ae93c4 | ||
|
caa1da342c | ||
|
b8a0e5f8a3 | ||
|
b43bffc940 | ||
|
1ad5681827 | ||
|
cf1d32e520 | ||
|
68f67eda54 | ||
|
ed2a054ca6 | ||
|
3fa685a0bb | ||
|
0d4813df13 | ||
|
5f2f35cbcf | ||
|
15fd4ea7c6 | ||
|
b21ca406c8 | ||
|
6925a3fefa | ||
|
c49c73bb3d | ||
|
8b743fbcd5 | ||
|
977156ba51 | ||
|
287277ef59 | ||
|
0e430e8b00 | ||
|
a6c22cf6e0 | ||
|
5c60f29fbf | ||
|
87c649c622 | ||
|
1f7c06d626 | ||
|
ef1235d3e8 | ||
|
ef60cbdc45 | ||
|
e7e85b8d73 | ||
|
bb5caa9bf1 | ||
|
3c959fecb2 | ||
|
4257bc446f | ||
|
a49ef347ff | ||
|
71ed4f60d7 | ||
|
7d2120fdd5 | ||
|
9af1937a71 |
42
Gemfile
42
Gemfile
@ -1,41 +1,21 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
gem 'volt', '0.9.5.pre4'
|
gem "opal"
|
||||||
|
gem 'opal-sprockets'
|
||||||
|
gem 'opal-browser'
|
||||||
|
|
||||||
# volt uses mongo as the default data store.
|
gem "rubyx" , "0.6" , path: "../rubyx"
|
||||||
gem 'volt-mongo', '~> 0.1.0'
|
|
||||||
|
|
||||||
gem "parslet" , git: "https://github.com/salama/parslet.git"
|
gem "rx-file" , :git => "https://github.com/ruby-x/rx-file"
|
||||||
#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"
|
|
||||||
|
|
||||||
# Asset compilation gems, they will be required when needed.
|
gem "sass"
|
||||||
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', '~> 3.2.0'
|
gem 'rspec'
|
||||||
gem 'opal-rspec', '~> 0.4.2'
|
gem 'capybara'
|
||||||
gem 'capybara', '~> 2.4.2'
|
gem 'selenium-webdriver'
|
||||||
gem 'selenium-webdriver', '~> 2.43.0'
|
gem 'chromedriver2-helper'
|
||||||
gem 'chromedriver2-helper', '~> 0.0.8'
|
gem 'poltergeist'
|
||||||
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
|
||||||
|
242
Gemfile.lock
242
Gemfile.lock
@ -1,186 +1,120 @@
|
|||||||
GIT
|
GIT
|
||||||
remote: https://github.com/salama/parslet.git
|
remote: https://github.com/ruby-x/rx-file
|
||||||
revision: beeb9b441a9ade1504f7f0e848d805e36a02c544
|
revision: 7c4a5546136d1bad065803da91778b209c18cb4d
|
||||||
specs:
|
specs:
|
||||||
parslet (1.7.0)
|
rx-file (0.3.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: ../salama
|
remote: ../rubyx
|
||||||
specs:
|
specs:
|
||||||
salama (0.2.0)
|
rubyx (0.6.0)
|
||||||
salama-object-file (~> 0.2)
|
parser (~> 2.3.0)
|
||||||
salama-reader (~> 0.2)
|
rx-file (~> 0.3)
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
bcrypt (3.1.10)
|
addressable (2.6.0)
|
||||||
bson (1.9.2)
|
public_suffix (>= 2.0.2, < 4.0)
|
||||||
bson_ext (1.9.2)
|
ast (2.4.0)
|
||||||
bson (~> 1.9.2)
|
capybara (3.13.2)
|
||||||
capybara (2.4.4)
|
addressable
|
||||||
mime-types (>= 1.16)
|
mini_mime (>= 0.1.3)
|
||||||
nokogiri (>= 1.3.3)
|
nokogiri (~> 1.8)
|
||||||
rack (>= 1.0.0)
|
rack (>= 1.6.0)
|
||||||
rack-test (>= 0.5.4)
|
rack-test (>= 0.6.3)
|
||||||
xpath (~> 2.0)
|
regexp_parser (~> 1.2)
|
||||||
childprocess (0.5.6)
|
xpath (~> 3.2)
|
||||||
|
childprocess (0.9.0)
|
||||||
ffi (~> 1.0, >= 1.0.11)
|
ffi (~> 1.0, >= 1.0.11)
|
||||||
chromedriver2-helper (0.0.8)
|
chromedriver2-helper (0.0.10)
|
||||||
nokogiri
|
nokogiri
|
||||||
cliver (0.3.2)
|
cliver (0.3.2)
|
||||||
coderay (1.1.0)
|
concurrent-ruby (1.1.4)
|
||||||
concurrent-ruby (0.8.0)
|
diff-lcs (1.3)
|
||||||
ref (~> 1.0, >= 1.0.5)
|
ffi (1.10.0)
|
||||||
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)
|
||||||
json (1.8.3)
|
mini_mime (1.0.1)
|
||||||
listen (3.0.3)
|
mini_portile2 (2.4.0)
|
||||||
rb-fsevent (>= 0.9.3)
|
minitest (5.11.3)
|
||||||
rb-inotify (>= 0.9)
|
nokogiri (1.10.1)
|
||||||
method_source (0.8.2)
|
mini_portile2 (~> 2.4.0)
|
||||||
mime-types (2.6.1)
|
opal (0.11.4)
|
||||||
mini_portile (0.6.2)
|
ast (>= 2.3.0)
|
||||||
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)
|
||||||
opal-rspec (0.4.3)
|
paggio (0.2.6)
|
||||||
opal (>= 0.7.0, < 0.9)
|
parser (2.3.3.1)
|
||||||
poltergeist (1.5.1)
|
ast (~> 2.2)
|
||||||
capybara (~> 2.1)
|
poltergeist (1.18.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)
|
||||||
pry (0.10.1)
|
public_suffix (3.0.3)
|
||||||
coderay (~> 1.1.0)
|
rack (2.0.6)
|
||||||
method_source (~> 0.8.1)
|
rack-test (1.1.0)
|
||||||
slop (~> 3.4)
|
rack (>= 1.0, < 3)
|
||||||
rack (1.5.5)
|
rb-fsevent (0.10.3)
|
||||||
rack-test (0.6.3)
|
rb-inotify (0.10.0)
|
||||||
rack (>= 1.0)
|
ffi (~> 1.0)
|
||||||
rb-fsevent (0.9.5)
|
regexp_parser (1.3.0)
|
||||||
rb-inotify (0.9.5)
|
rspec (3.8.0)
|
||||||
ffi (>= 0.5.0)
|
rspec-core (~> 3.8.0)
|
||||||
ref (1.0.5)
|
rspec-expectations (~> 3.8.0)
|
||||||
rspec (3.2.0)
|
rspec-mocks (~> 3.8.0)
|
||||||
rspec-core (~> 3.2.0)
|
rspec-core (3.8.0)
|
||||||
rspec-expectations (~> 3.2.0)
|
rspec-support (~> 3.8.0)
|
||||||
rspec-mocks (~> 3.2.0)
|
rspec-expectations (3.8.2)
|
||||||
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.2.0)
|
rspec-support (~> 3.8.0)
|
||||||
rspec-mocks (3.2.1)
|
rspec-mocks (3.8.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.2.0)
|
rspec-support (~> 3.8.0)
|
||||||
rspec-support (3.2.2)
|
rspec-support (3.8.0)
|
||||||
rubyzip (1.1.7)
|
rubyzip (1.2.2)
|
||||||
sass (3.4.16)
|
sass (3.7.3)
|
||||||
selenium-webdriver (2.43.0)
|
sass-listen (~> 4.0.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)
|
||||||
multi_json (~> 1.0)
|
rubyzip (~> 1.2, >= 1.2.2)
|
||||||
rubyzip (~> 1.0)
|
|
||||||
websocket (~> 1.0)
|
|
||||||
slop (3.6.0)
|
|
||||||
sourcemap (0.1.1)
|
sourcemap (0.1.1)
|
||||||
sprockets (3.2.0)
|
sprockets (3.7.2)
|
||||||
rack (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
susy (2.2.5)
|
rack (> 1, < 3)
|
||||||
sass (>= 3.3.0, < 3.5)
|
tilt (2.0.9)
|
||||||
thin (1.6.3)
|
websocket-driver (0.7.0)
|
||||||
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.2)
|
websocket-extensions (0.1.3)
|
||||||
xpath (2.0.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.3)
|
nokogiri (~> 1.8)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
bson_ext (~> 1.9.0)
|
capybara
|
||||||
capybara (~> 2.4.2)
|
chromedriver2-helper
|
||||||
chromedriver2-helper (~> 0.0.8)
|
|
||||||
concurrent-ruby-ext (~> 0.8.0)
|
|
||||||
csso-rails (~> 0.3.4)
|
|
||||||
minitest
|
minitest
|
||||||
opal-rspec (~> 0.4.2)
|
opal
|
||||||
parslet!
|
opal-browser
|
||||||
poltergeist (~> 1.5.0)
|
opal-sprockets
|
||||||
rspec (~> 3.2.0)
|
poltergeist
|
||||||
salama!
|
rspec
|
||||||
salama-arm!
|
rubyx (= 0.6)!
|
||||||
salama-object-file!
|
rx-file!
|
||||||
salama-reader!
|
sass
|
||||||
selenium-webdriver (~> 2.43.0)
|
selenium-webdriver
|
||||||
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.10.5
|
1.17.2
|
||||||
|
127
README.md
127
README.md
@ -1,36 +1,117 @@
|
|||||||
# 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.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- On the left are the classes of the system. Next idea is to have hover info about them.
|
## Views
|
||||||
- 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
|
|
||||||
|
|
||||||
So lots to do, but a good start.
|
From left to right there are several views showing different data and controls.
|
||||||
|
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
|
||||||
|
|
||||||
I don't want to use gdb anymore, and it would be easier without using the qemu setup, so:
|
Next is a view of the Soml source. The Source is reconstructed from the ast as html.
|
||||||
|
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.
|
||||||
|
|
||||||
- single step debugging of the register machine level (as close to arm as need be)
|
While stepping through the code, those parts of the code that are active get highlighted in blue.
|
||||||
- visual transitions for steps
|
|
||||||
- visualisation of data in registers (some kind of link to the object)
|
Currently stepping is done only in register instructions, which means that depending on the source
|
||||||
- show the current instruction and a few around
|
constructs it may take many steps for the cursor to move on.
|
||||||
- show vm object (message etc)
|
|
||||||
- show effect of register transitions on vm objects
|
Each step will show progress on the register level though (next view)
|
||||||
- visualize vm object content (again some links)
|
|
||||||
|
|
||||||
|
|
||||||
# Space
|
### Register Instruction view
|
||||||
|
|
||||||
- Visualise the object space in some way
|
Salama defines a register machine level which is quite close to the arm machine, but with more
|
||||||
- Visualise single object, bit like atoms
|
sensible names. It has 16 registers (below) and an instruction set that is useful for Soml.
|
||||||
- values immediate
|
|
||||||
- objects as link
|
Data movement related instruction implement an indexed get and set. There is also Constant load and
|
||||||
|
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
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
// 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 ;
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
# Specify which components you wish to include when
|
|
||||||
# the "home" component loads.
|
|
@ -1,10 +0,0 @@
|
|||||||
# 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.
|
|
@ -1,8 +0,0 @@
|
|||||||
# 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 '/', {}
|
|
@ -1,12 +0,0 @@
|
|||||||
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
|
|
@ -1,28 +0,0 @@
|
|||||||
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
|
|
@ -1,43 +0,0 @@
|
|||||||
# 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
|
|
@ -1,55 +0,0 @@
|
|||||||
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
|
|
@ -1,26 +0,0 @@
|
|||||||
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
|
|
@ -1,12 +0,0 @@
|
|||||||
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
|
|
@ -1,31 +0,0 @@
|
|||||||
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
|
|
@ -1,10 +0,0 @@
|
|||||||
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
|
|
@ -1,36 +0,0 @@
|
|||||||
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
|
|
@ -1,23 +0,0 @@
|
|||||||
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
|
|
@ -1,11 +0,0 @@
|
|||||||
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
|
|
@ -1,17 +0,0 @@
|
|||||||
<: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>
|
|
@ -1,23 +0,0 @@
|
|||||||
<: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>
|
|
@ -1,16 +0,0 @@
|
|||||||
<:Title>
|
|
||||||
Home
|
|
||||||
|
|
||||||
<:Body>
|
|
||||||
<:classes />
|
|
||||||
|
|
||||||
<div class="file-view">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<:sources />
|
|
||||||
|
|
||||||
<:blocks />
|
|
||||||
|
|
||||||
<:status/>
|
|
||||||
|
|
||||||
<:registers/>
|
|
@ -1,12 +0,0 @@
|
|||||||
<:Title>
|
|
||||||
{{ view main_path, "title", {controller_group: 'main'} }}
|
|
||||||
|
|
||||||
<:Body>
|
|
||||||
<div class="debugger_view">
|
|
||||||
|
|
||||||
<:volt:notices />
|
|
||||||
|
|
||||||
{{ view main_path, 'body', {controller_group: 'main'} }}
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
@ -1,15 +0,0 @@
|
|||||||
<:Title>
|
|
||||||
objects index
|
|
||||||
|
|
||||||
<:Body>
|
|
||||||
<ul sid={{attrs.id}}>
|
|
||||||
<li>
|
|
||||||
<span>{{class_header(attrs.id)}}</span>
|
|
||||||
</li>
|
|
||||||
<li> -------------------------</li>
|
|
||||||
{{content(attrs.id).each do |con3| }}
|
|
||||||
<li>
|
|
||||||
<a href="#">{{con3[0]}}</a>
|
|
||||||
</li>
|
|
||||||
{{end}}
|
|
||||||
</ul>
|
|
@ -1,19 +0,0 @@
|
|||||||
<: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>
|
|
@ -1,14 +0,0 @@
|
|||||||
<: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>
|
|
@ -1,17 +0,0 @@
|
|||||||
<: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>
|
|
98
assets/css/app.css.sass
Normal file
98
assets/css/app.css.sass
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
|
||||||
|
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
|
45
assets/css/menu.css.sass
Normal file
45
assets/css/menu.css.sass
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
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
|
5
codes/a_puti.soml
Normal file
5
codes/a_puti.soml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class Object
|
||||||
|
int main()
|
||||||
|
return 55.puti()
|
||||||
|
end
|
||||||
|
end
|
22
codes/fibo_recur.soml
Normal file
22
codes/fibo_recur.soml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
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
|
20
codes/fibo_while.soml
Normal file
20
codes/fibo_while.soml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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
|
6
codes/hello_world.soml
Normal file
6
codes/hello_world.soml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class Object
|
||||||
|
int main()
|
||||||
|
"Hello World".putstring()
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
13
codes/if_called.soml
Normal file
13
codes/if_called.soml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
class Object
|
||||||
|
int itest(int n)
|
||||||
|
if_zero( n - 12)
|
||||||
|
"then".putstring()
|
||||||
|
else
|
||||||
|
"else".putstring()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
int main()
|
||||||
|
itest(20)
|
||||||
|
end
|
||||||
|
end
|
10
codes/if_else.soml
Normal file
10
codes/if_else.soml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
class Object
|
||||||
|
int main()
|
||||||
|
int n = 14
|
||||||
|
if_plus( n - 12)
|
||||||
|
"then".putstring()
|
||||||
|
else
|
||||||
|
"else".putstring()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
23
codes/layout.soml
Normal file
23
codes/layout.soml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
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
|
8
codes/offset_check.soml
Normal file
8
codes/offset_check.soml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class Object
|
||||||
|
int puts(Word str)
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
int main()
|
||||||
|
puts("Hello")
|
||||||
|
end
|
||||||
|
end
|
23
codes/times.soml
Normal file
23
codes/times.soml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
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
|
12
codes/while.soml
Normal file
12
codes/while.soml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class Object
|
||||||
|
|
||||||
|
int main()
|
||||||
|
int i = 5
|
||||||
|
while_plus(i)
|
||||||
|
"out ".putstring()
|
||||||
|
i = i - 1
|
||||||
|
end
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
20
config.ru
20
config.ru
@ -1,4 +1,16 @@
|
|||||||
# Run via rack server
|
require 'bundler'
|
||||||
require 'bundler/setup'
|
Bundler.require
|
||||||
require 'volt/server'
|
require 'tilt/erb'
|
||||||
run Volt::Server.new.app
|
require "opal"
|
||||||
|
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
136
config/app.rb
@ -1,136 +0,0 @@
|
|||||||
# 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
|
|
@ -1,15 +0,0 @@
|
|||||||
<!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>
|
|
@ -1,6 +0,0 @@
|
|||||||
# Specify which components you wish to include when
|
|
||||||
# the "home" component loads.
|
|
||||||
|
|
||||||
|
|
||||||
Opal.use_gem("salama-reader")
|
|
||||||
Opal.use_gem("salama-object-file")
|
|
@ -1,10 +0,0 @@
|
|||||||
# 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.
|
|
@ -1,2 +0,0 @@
|
|||||||
Opal.use_gem "salama"
|
|
||||||
Opal.use_gem "salama-arm"
|
|
@ -1,7 +0,0 @@
|
|||||||
# 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 '/', {}
|
|
12
index.html.erb
Normal file
12
index.html.erb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<!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>
|
19
lib/base/constant_view.rb
Normal file
19
lib/base/constant_view.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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
|
90
lib/base/element_view.rb
Normal file
90
lib/base/element_view.rb
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# 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
|
74
lib/base/list_view.rb
Normal file
74
lib/base/list_view.rb
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
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
|
62
lib/debugger.js.rb
Normal file
62
lib/debugger.js.rb
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
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)
|
44
lib/views/classes_view.rb
Normal file
44
lib/views/classes_view.rb
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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
|
120
lib/views/html_converter.rb
Normal file
120
lib/views/html_converter.rb
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
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
|
89
lib/views/left_view.rb
Normal file
89
lib/views/left_view.rb
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
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
|
43
lib/views/mom_view.rb
Normal file
43
lib/views/mom_view.rb
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
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
|
73
lib/views/object_view.rb
Normal file
73
lib/views/object_view.rb
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
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
|
69
lib/views/ref_view.rb
Normal file
69
lib/views/ref_view.rb
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
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
|
54
lib/views/registers_view.rb
Normal file
54
lib/views/registers_view.rb
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
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
|
42
lib/views/risc_view.rb
Normal file
42
lib/views/risc_view.rb
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
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
|
85
lib/views/status_view.rb
Normal file
85
lib/views/status_view.rb
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
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
|
46
lib/views/vool_view.rb
Normal file
46
lib/views/vool_view.rb
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
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
|
@ -1,5 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe '', type: :feature do
|
|
||||||
# Specs here
|
|
||||||
end
|
|
@ -1,5 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe '', type: :feature do
|
|
||||||
# Specs here
|
|
||||||
end
|
|
@ -1,5 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe '', type: :feature do
|
|
||||||
# Specs here
|
|
||||||
end
|
|
@ -1,5 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe '', type: :feature do
|
|
||||||
# Specs here
|
|
||||||
end
|
|
@ -1,5 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe '', type: :feature do
|
|
||||||
# Specs here
|
|
||||||
end
|
|
@ -1,5 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe '', type: :feature do
|
|
||||||
# Specs here
|
|
||||||
end
|
|
Binary file not shown.
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 375 KiB |
Loading…
x
Reference in New Issue
Block a user