Compare commits
48 Commits
Author | SHA1 | Date | |
---|---|---|---|
83b9511df3 | |||
719f026d0f | |||
d7e0cd665f | |||
ef321dab26 | |||
f942ed719a | |||
a779daf205 | |||
9837461a86 | |||
08fba7129b | |||
5583a7a56c | |||
3d2dadbd62 | |||
c6d5824dff | |||
a1f1d9d6a4 | |||
2b9f16dad4 | |||
33ee57e605 | |||
7b82ff31dd | |||
8ed2a03ea9 | |||
0926f1f85f | |||
72a2d22215 | |||
abb22f524b | |||
b91fabdd90 | |||
878ec9aecc | |||
50367abcbb | |||
64078cc331 | |||
65d95de885 | |||
bdfafd17c8 | |||
ab08fcc7c1 | |||
cfc6f09ec1 | |||
1728cc1b25 | |||
5bd6b3517d | |||
69e51a1037 | |||
ba8768e374 | |||
33b0260bfb | |||
b81c8e69b7 | |||
eba80177ae | |||
9afaeba302 | |||
4c4d90385f | |||
e8a5a20db1 | |||
08beaa2d93 | |||
bb24a6cae5 | |||
d8a3657365 | |||
a2f3daa828 | |||
9383f0d75e | |||
264a52c184 | |||
3bad4cc570 | |||
56521fd5ed | |||
a0b37977a9 | |||
9c7a333127 | |||
485f3134dd |
47
.gitignore
vendored
47
.gitignore
vendored
@ -1,42 +1,9 @@
|
|||||||
# database
|
|
||||||
db
|
|
||||||
|
|
||||||
# rdoc generated
|
|
||||||
rdoc
|
|
||||||
|
|
||||||
# yard generated
|
|
||||||
doc
|
|
||||||
.yardoc
|
|
||||||
|
|
||||||
# bundler
|
|
||||||
.bundle
|
.bundle
|
||||||
*.gem
|
.config
|
||||||
|
.yardoc
|
||||||
# jeweler generated
|
tmp
|
||||||
pkg
|
.idea
|
||||||
|
.yardoc
|
||||||
#
|
.sass-cache
|
||||||
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
|
||||||
#
|
|
||||||
# For MacOS:
|
|
||||||
#
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
compiled
|
||||||
# For TextMate
|
|
||||||
#*.tmproj
|
|
||||||
#tmtags
|
|
||||||
|
|
||||||
# For emacs:
|
|
||||||
#*~
|
|
||||||
#\#*
|
|
||||||
#.\#*
|
|
||||||
|
|
||||||
# For vim:
|
|
||||||
#*.swp
|
|
||||||
|
|
||||||
|
|
||||||
# Object files
|
|
||||||
*.o
|
|
||||||
log
|
|
||||||
|
|
||||||
tmp/
|
|
46
Gemfile
46
Gemfile
@ -1,17 +1,41 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
gem 'opal-react', :path => '../react.rb'
|
gem 'volt', '0.9.5.pre4'
|
||||||
gem 'opal-jquery'
|
|
||||||
gem 'react-source'
|
|
||||||
|
|
||||||
gem "parslet" , github: "salama/parslet"
|
# volt uses mongo as the default data store.
|
||||||
gem "salama" , github: "salama/salama"
|
gem 'volt-mongo', '~> 0.1.0'
|
||||||
gem "salama-reader" , github: "salama/salama-reader"
|
|
||||||
gem "salama-arm" , github: "salama/salama-arm"
|
|
||||||
gem "salama-object-file" , github: "salama/salama-object-file"
|
|
||||||
gem "susy"
|
|
||||||
|
|
||||||
group :development do
|
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"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# Testing dependencies
|
||||||
gem "minitest"
|
gem "minitest"
|
||||||
gem "rubygems-tasks"
|
gem 'rspec', '~> 3.2.0'
|
||||||
|
gem 'opal-rspec', '~> 0.4.2'
|
||||||
|
gem 'capybara', '~> 2.4.2'
|
||||||
|
gem 'selenium-webdriver', '~> 2.43.0'
|
||||||
|
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
|
||||||
|
157
Gemfile.lock
157
Gemfile.lock
@ -1,83 +1,186 @@
|
|||||||
GIT
|
GIT
|
||||||
remote: git://github.com/salama/parslet.git
|
remote: https://github.com/salama/parslet.git
|
||||||
revision: beeb9b441a9ade1504f7f0e848d805e36a02c544
|
revision: beeb9b441a9ade1504f7f0e848d805e36a02c544
|
||||||
specs:
|
specs:
|
||||||
parslet (1.7.0)
|
parslet (1.7.0)
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: git://github.com/salama/salama-arm.git
|
remote: https://github.com/salama/salama-arm.git
|
||||||
revision: 0bd5091e3f284ecf040e0086a41d2449cd5afb7a
|
revision: 0bd5091e3f284ecf040e0086a41d2449cd5afb7a
|
||||||
specs:
|
specs:
|
||||||
salama-arm (0.0.1)
|
salama-arm (0.0.1)
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: git://github.com/salama/salama-object-file.git
|
remote: https://github.com/salama/salama-object-file.git
|
||||||
revision: fbae6a02764dbe97e01e4833f9ffffe09879b100
|
revision: fbae6a02764dbe97e01e4833f9ffffe09879b100
|
||||||
specs:
|
specs:
|
||||||
salama-object-file (0.2.0)
|
salama-object-file (0.2.0)
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: git://github.com/salama/salama-reader.git
|
remote: https://github.com/salama/salama-reader.git
|
||||||
revision: 841592c667acea1e796f950851262e6938b231bc
|
revision: 841592c667acea1e796f950851262e6938b231bc
|
||||||
specs:
|
specs:
|
||||||
salama-reader (0.2.0)
|
salama-reader (0.2.0)
|
||||||
parslet (~> 1.7.0)
|
parslet (~> 1.7.0)
|
||||||
|
|
||||||
GIT
|
PATH
|
||||||
remote: git://github.com/salama/salama.git
|
remote: ../salama
|
||||||
revision: 3fb08acf3f83aa403b095aa60be1702419d8a66d
|
|
||||||
specs:
|
specs:
|
||||||
salama (0.2.0)
|
salama (0.2.0)
|
||||||
salama-object-file (~> 0.2)
|
salama-object-file (~> 0.2)
|
||||||
salama-reader (~> 0.2)
|
salama-reader (~> 0.2)
|
||||||
|
|
||||||
PATH
|
|
||||||
remote: ../react.rb
|
|
||||||
specs:
|
|
||||||
opal-react (0.2.2)
|
|
||||||
opal
|
|
||||||
opal-activesupport
|
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
|
bcrypt (3.1.10)
|
||||||
|
bson (1.9.2)
|
||||||
|
bson_ext (1.9.2)
|
||||||
|
bson (~> 1.9.2)
|
||||||
|
capybara (2.4.4)
|
||||||
|
mime-types (>= 1.16)
|
||||||
|
nokogiri (>= 1.3.3)
|
||||||
|
rack (>= 1.0.0)
|
||||||
|
rack-test (>= 0.5.4)
|
||||||
|
xpath (~> 2.0)
|
||||||
|
childprocess (0.5.6)
|
||||||
|
ffi (~> 1.0, >= 1.0.11)
|
||||||
|
chromedriver2-helper (0.0.8)
|
||||||
|
nokogiri
|
||||||
|
cliver (0.3.2)
|
||||||
|
coderay (1.1.0)
|
||||||
|
concurrent-ruby (0.8.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)
|
||||||
minitest (5.7.0)
|
json (1.8.3)
|
||||||
|
listen (3.0.3)
|
||||||
|
rb-fsevent (>= 0.9.3)
|
||||||
|
rb-inotify (>= 0.9)
|
||||||
|
method_source (0.8.2)
|
||||||
|
mime-types (2.6.1)
|
||||||
|
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)
|
opal (0.8.0)
|
||||||
hike (~> 1.2)
|
hike (~> 1.2)
|
||||||
sourcemap (~> 0.1.0)
|
sourcemap (~> 0.1.0)
|
||||||
sprockets (~> 3.1)
|
sprockets (~> 3.1)
|
||||||
tilt (>= 1.4)
|
tilt (>= 1.4)
|
||||||
opal-activesupport (0.1.0)
|
opal-rspec (0.4.3)
|
||||||
opal (>= 0.5.0, < 1.0.0)
|
opal (>= 0.7.0, < 0.9)
|
||||||
opal-jquery (0.4.0)
|
poltergeist (1.5.1)
|
||||||
opal (>= 0.7.0, < 0.9.0)
|
capybara (~> 2.1)
|
||||||
rack (1.6.4)
|
cliver (~> 0.3.1)
|
||||||
react-source (0.13.3)
|
multi_json (~> 1.0)
|
||||||
rubygems-tasks (0.2.4)
|
websocket-driver (>= 0.2.0)
|
||||||
|
pry (0.10.1)
|
||||||
|
coderay (~> 1.1.0)
|
||||||
|
method_source (~> 0.8.1)
|
||||||
|
slop (~> 3.4)
|
||||||
|
rack (1.5.5)
|
||||||
|
rack-test (0.6.3)
|
||||||
|
rack (>= 1.0)
|
||||||
|
rb-fsevent (0.9.5)
|
||||||
|
rb-inotify (0.9.5)
|
||||||
|
ffi (>= 0.5.0)
|
||||||
|
ref (1.0.5)
|
||||||
|
rspec (3.2.0)
|
||||||
|
rspec-core (~> 3.2.0)
|
||||||
|
rspec-expectations (~> 3.2.0)
|
||||||
|
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)
|
||||||
|
rspec-support (~> 3.2.0)
|
||||||
|
rspec-mocks (3.2.1)
|
||||||
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
|
rspec-support (~> 3.2.0)
|
||||||
|
rspec-support (3.2.2)
|
||||||
|
rubyzip (1.1.7)
|
||||||
sass (3.4.16)
|
sass (3.4.16)
|
||||||
|
selenium-webdriver (2.43.0)
|
||||||
|
childprocess (~> 0.5)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
rubyzip (~> 1.0)
|
||||||
|
websocket (~> 1.0)
|
||||||
|
slop (3.6.0)
|
||||||
sourcemap (0.1.1)
|
sourcemap (0.1.1)
|
||||||
sprockets (3.2.0)
|
sprockets (3.2.0)
|
||||||
rack (~> 1.0)
|
rack (~> 1.0)
|
||||||
susy (2.2.5)
|
susy (2.2.5)
|
||||||
sass (>= 3.3.0, < 3.5)
|
sass (>= 3.3.0, < 3.5)
|
||||||
|
thin (1.6.3)
|
||||||
|
daemons (~> 1.0, >= 1.0.9)
|
||||||
|
eventmachine (~> 1.0)
|
||||||
|
rack (~> 1.0)
|
||||||
|
thor (0.19.1)
|
||||||
tilt (2.0.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.2)
|
||||||
|
xpath (2.0.0)
|
||||||
|
nokogiri (~> 1.3)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
bson_ext (~> 1.9.0)
|
||||||
|
capybara (~> 2.4.2)
|
||||||
|
chromedriver2-helper (~> 0.0.8)
|
||||||
|
concurrent-ruby-ext (~> 0.8.0)
|
||||||
|
csso-rails (~> 0.3.4)
|
||||||
minitest
|
minitest
|
||||||
opal-jquery
|
opal-rspec (~> 0.4.2)
|
||||||
opal-react!
|
|
||||||
parslet!
|
parslet!
|
||||||
react-source
|
poltergeist (~> 1.5.0)
|
||||||
rubygems-tasks
|
rspec (~> 3.2.0)
|
||||||
salama!
|
salama!
|
||||||
salama-arm!
|
salama-arm!
|
||||||
salama-object-file!
|
salama-object-file!
|
||||||
salama-reader!
|
salama-reader!
|
||||||
susy
|
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.10.5
|
1.10.5
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
|
|
||||||
require "instruction_view"
|
|
||||||
|
|
||||||
class BlockView
|
|
||||||
|
|
||||||
include React::Component
|
|
||||||
required_param :interpreter
|
|
||||||
|
|
||||||
define_state :block => []
|
|
||||||
define_state :block_name => ""
|
|
||||||
|
|
||||||
before_mount do
|
|
||||||
interpreter.register_event(:instruction_changed, self)
|
|
||||||
update_block
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_block
|
|
||||||
return unless interpreter.instruction
|
|
||||||
block_name! interpreter.block.name
|
|
||||||
codes = interpreter.block.codes.dup
|
|
||||||
slice = codes.index(interpreter.instruction) #- 1
|
|
||||||
codes.shift( slice ) if slice >= 0
|
|
||||||
codes.pop while(codes.length > 4)
|
|
||||||
block! codes
|
|
||||||
end
|
|
||||||
|
|
||||||
def instruction_changed
|
|
||||||
update_block
|
|
||||||
end
|
|
||||||
|
|
||||||
def render
|
|
||||||
return unless block
|
|
||||||
div.block_view do
|
|
||||||
div do
|
|
||||||
h4 { method_name}
|
|
||||||
h4 {"Block: #{block_name}"}
|
|
||||||
end
|
|
||||||
block.each do |code|
|
|
||||||
InstructionView :interpreter => interpreter , :instruction => code
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def method_name
|
|
||||||
bl = interpreter.block
|
|
||||||
return bl.method if bl.method.is_a? String
|
|
||||||
"#{bl.method.for_class.name}.#{bl.method.name}"
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,16 +0,0 @@
|
|||||||
class ClassView
|
|
||||||
include React::Component
|
|
||||||
|
|
||||||
required_param :classes, type: {}
|
|
||||||
|
|
||||||
def render
|
|
||||||
div.classes do
|
|
||||||
h4 { "Classes" }
|
|
||||||
classes.each do |name , clas|
|
|
||||||
div.one_class do
|
|
||||||
clas.name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,37 +0,0 @@
|
|||||||
|
|
||||||
require "register_view"
|
|
||||||
require "class_view"
|
|
||||||
require "source_view"
|
|
||||||
require "block_view"
|
|
||||||
require "status_view"
|
|
||||||
|
|
||||||
class Debugger
|
|
||||||
|
|
||||||
include React::Component
|
|
||||||
required_param :machine , :type => Virtual::Machine
|
|
||||||
define_state :interpreter => Interpreter.new
|
|
||||||
|
|
||||||
before_mount do
|
|
||||||
code = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:putstring, [] ,Ast::StringExpression.new("Hello again"))])
|
|
||||||
Virtual::Compiler.compile( code , machine.space.get_main )
|
|
||||||
machine.run_before "Register::CallImplementation"
|
|
||||||
interpreter.start machine.init
|
|
||||||
end
|
|
||||||
def render
|
|
||||||
div.debugger_view do
|
|
||||||
ClassView classes: machine.space.classes
|
|
||||||
div.file_view do
|
|
||||||
"Future Source code view"
|
|
||||||
end
|
|
||||||
SourceView :interpreter => interpreter
|
|
||||||
BlockView :interpreter => interpreter
|
|
||||||
StatusView :interpreter => interpreter
|
|
||||||
div.registers_view do
|
|
||||||
interpreter.registers.each do |r , oid|
|
|
||||||
RegisterView interpreter: interpreter , register: r
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,28 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
class InstructionView
|
|
||||||
|
|
||||||
include React::Component
|
|
||||||
required_param :interpreter
|
|
||||||
required_param :instruction
|
|
||||||
|
|
||||||
define_state :active => ""
|
|
||||||
|
|
||||||
before_mount do
|
|
||||||
check_active interpreter.instruction
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_active i
|
|
||||||
active! instruction == i ? "bright" : ""
|
|
||||||
|
|
||||||
end
|
|
||||||
def instruction_changed old , ins
|
|
||||||
check_active ins
|
|
||||||
end
|
|
||||||
|
|
||||||
def render
|
|
||||||
div :class => active do
|
|
||||||
instruction.to_s if instruction
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
16
app/main.rb
16
app/main.rb
@ -1,16 +0,0 @@
|
|||||||
require 'opal'
|
|
||||||
require "opal/parser"
|
|
||||||
|
|
||||||
require "salama"
|
|
||||||
require "interpreter"
|
|
||||||
|
|
||||||
require 'opal-react'
|
|
||||||
|
|
||||||
require "debugger"
|
|
||||||
|
|
||||||
require 'opal-jquery'
|
|
||||||
|
|
||||||
Document.ready? do # Document.ready? is a opal-jquery method.
|
|
||||||
machine = Virtual.machine.boot
|
|
||||||
React.render( React.create_element( Debugger , :machine => machine ), Element['#content'] )
|
|
||||||
end
|
|
@ -1,5 +1,7 @@
|
|||||||
|
// Place your apps css here
|
||||||
@import "susy";
|
@import "susy";
|
||||||
|
|
||||||
|
|
||||||
$susy: (
|
$susy: (
|
||||||
columns: 24 ,
|
columns: 24 ,
|
||||||
gutter-position: split ,
|
gutter-position: split ,
|
||||||
@ -7,8 +9,13 @@ $susy: (
|
|||||||
|
|
||||||
.debugger-view { @include container(90%); }
|
.debugger-view { @include container(90%); }
|
||||||
|
|
||||||
.classes { @include span(3); }
|
.classes {
|
||||||
|
@include span(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.one-class {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
.file-view {
|
.file-view {
|
||||||
@include span(4);
|
@include span(4);
|
||||||
margin: span(1);
|
margin: span(1);
|
||||||
@ -18,7 +25,7 @@ $susy: (
|
|||||||
|
|
||||||
.block-view {
|
.block-view {
|
||||||
@include span(4);
|
@include span(4);
|
||||||
margin-right: span(3);
|
margin-right: span(2);
|
||||||
height: 200px;
|
height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,10 +38,22 @@ $susy: (
|
|||||||
}
|
}
|
||||||
|
|
||||||
.register-view {
|
.register-view {
|
||||||
@include gallery(3);
|
@include gallery(4);
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
@include span(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
@include span(18)
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-head {
|
||||||
|
background-color: #C5FFD9;
|
||||||
|
}
|
||||||
|
|
||||||
.bright {
|
.bright {
|
||||||
background-color: orange ;
|
background-color: orange ;
|
||||||
}
|
}
|
59
app/main/assets/css/menu.css
Normal file
59
app/main/assets/css/menu.css
Normal 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;
|
||||||
|
}
|
2
app/main/config/dependencies.rb
Normal file
2
app/main/config/dependencies.rb
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Specify which components you wish to include when
|
||||||
|
# the "home" component loads.
|
10
app/main/config/initializers/boot.rb
Normal file
10
app/main/config/initializers/boot.rb
Normal 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.
|
8
app/main/config/routes.rb
Normal file
8
app/main/config/routes.rb
Normal 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 '/', {}
|
12
app/main/controllers/blocks_controller.rb
Normal file
12
app/main/controllers/blocks_controller.rb
Normal 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
|
28
app/main/controllers/classes_controller.rb
Normal file
28
app/main/controllers/classes_controller.rb
Normal 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
|
43
app/main/controllers/main_controller.rb
Normal file
43
app/main/controllers/main_controller.rb
Normal 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
|
55
app/main/controllers/objects_controller.rb
Normal file
55
app/main/controllers/objects_controller.rb
Normal 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
|
26
app/main/controllers/registers_controller.rb
Normal file
26
app/main/controllers/registers_controller.rb
Normal 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
|
12
app/main/controllers/sources_controller.rb
Normal file
12
app/main/controllers/sources_controller.rb
Normal 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
|
31
app/main/controllers/status_controller.rb
Normal file
31
app/main/controllers/status_controller.rb
Normal 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
|
10
app/main/models/blocks_model.rb
Normal file
10
app/main/models/blocks_model.rb
Normal 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
|
36
app/main/models/register_model.rb
Normal file
36
app/main/models/register_model.rb
Normal 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
|
23
app/main/models/source_model.rb
Normal file
23
app/main/models/source_model.rb
Normal 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
|
11
app/main/tasks/parse_task.rb
Normal file
11
app/main/tasks/parse_task.rb
Normal 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
|
17
app/main/views/blocks/index.html
Normal file
17
app/main/views/blocks/index.html
Normal 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>
|
23
app/main/views/classes/index.html
Normal file
23
app/main/views/classes/index.html
Normal 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>
|
16
app/main/views/main/index.html
Normal file
16
app/main/views/main/index.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<:Title>
|
||||||
|
Home
|
||||||
|
|
||||||
|
<:Body>
|
||||||
|
<:classes />
|
||||||
|
|
||||||
|
<div class="file-view">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<:sources />
|
||||||
|
|
||||||
|
<:blocks />
|
||||||
|
|
||||||
|
<:status/>
|
||||||
|
|
||||||
|
<:registers/>
|
12
app/main/views/main/main.html
Normal file
12
app/main/views/main/main.html
Normal 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>
|
15
app/main/views/objects/index.html
Normal file
15
app/main/views/objects/index.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<: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>
|
19
app/main/views/registers/index.html
Normal file
19
app/main/views/registers/index.html
Normal 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>
|
14
app/main/views/sources/index.html
Normal file
14
app/main/views/sources/index.html
Normal 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>
|
17
app/main/views/status/index.html
Normal file
17
app/main/views/status/index.html
Normal 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>
|
@ -1,64 +0,0 @@
|
|||||||
|
|
||||||
class RegisterView
|
|
||||||
|
|
||||||
include React::Component
|
|
||||||
required_param :interpreter
|
|
||||||
required_param :register
|
|
||||||
|
|
||||||
define_state :objects_id
|
|
||||||
define_state :fields => []
|
|
||||||
|
|
||||||
before_mount do
|
|
||||||
interpreter.register_event(:register_changed, self)
|
|
||||||
interpreter.register_event(:object_changed, self)
|
|
||||||
register_changed( register , nil , interpreter.registers[register])
|
|
||||||
end
|
|
||||||
|
|
||||||
def register_changed reg , old , value
|
|
||||||
reg = reg.symbol unless reg.is_a? Symbol
|
|
||||||
return unless reg == register
|
|
||||||
objects_id! value
|
|
||||||
calc_fields
|
|
||||||
end
|
|
||||||
|
|
||||||
def object_changed reg
|
|
||||||
reg = reg.symbol unless reg.is_a? Symbol
|
|
||||||
return unless reg == register
|
|
||||||
puts "Object changed in #{reg}"
|
|
||||||
calc_fields
|
|
||||||
end
|
|
||||||
|
|
||||||
def calc_fields
|
|
||||||
#puts "My id #{objects_id} , #{objects_id.class}"
|
|
||||||
object = Virtual.machine.objects[objects_id]
|
|
||||||
if object and ! object.is_a?(String)
|
|
||||||
has_fields = []
|
|
||||||
clazz = object.class.name.split("::").last
|
|
||||||
#puts "found #{clazz}"
|
|
||||||
has_fields << clazz
|
|
||||||
object.get_instance_variables.each do |variable|
|
|
||||||
f = object.get_instance_variable(variable)
|
|
||||||
has_fields << f
|
|
||||||
end
|
|
||||||
fields! has_fields
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def render
|
|
||||||
div.register_view do
|
|
||||||
div do
|
|
||||||
objects_id.to_s
|
|
||||||
end
|
|
||||||
fields.each do |attribute|
|
|
||||||
div.col_md_12 do
|
|
||||||
"#{marker(attribute)} - #{attribute.object_id}".span
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def marker var
|
|
||||||
return "W" if var.is_a? String
|
|
||||||
var.class.name.split("::").last[0]
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,38 +0,0 @@
|
|||||||
class SourceView
|
|
||||||
|
|
||||||
include React::Component
|
|
||||||
|
|
||||||
required_param :interpreter
|
|
||||||
|
|
||||||
define_state :sources => []
|
|
||||||
|
|
||||||
before_mount do
|
|
||||||
interpreter.register_event(:instruction_changed, self)
|
|
||||||
instruction_changed nil , interpreter.instruction
|
|
||||||
end
|
|
||||||
|
|
||||||
def instruction_changed old , ins
|
|
||||||
text = ins ? source_text(ins.source) : "exit"
|
|
||||||
return if sources.last == text
|
|
||||||
sources << text
|
|
||||||
sources.shift if sources.length > 5
|
|
||||||
sources! sources
|
|
||||||
end
|
|
||||||
|
|
||||||
def render
|
|
||||||
div.source_view do
|
|
||||||
h4 {"Virtual Machine Instruction"}
|
|
||||||
sources.each do |s|
|
|
||||||
s.br
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def source_text source
|
|
||||||
if source.is_a? Virtual::Instruction
|
|
||||||
return source.class.name
|
|
||||||
else
|
|
||||||
return "Method: #{source.name}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,41 +0,0 @@
|
|||||||
|
|
||||||
class StatusView
|
|
||||||
|
|
||||||
include React::Component
|
|
||||||
required_param :interpreter
|
|
||||||
|
|
||||||
define_state :state => "starting"
|
|
||||||
define_state :stdout
|
|
||||||
|
|
||||||
before_mount do
|
|
||||||
interpreter.register_event(:instruction_changed, self)
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_state
|
|
||||||
state! interpreter.state
|
|
||||||
stdout! interpreter.stdout
|
|
||||||
end
|
|
||||||
|
|
||||||
def instruction_changed old , nex
|
|
||||||
update_state
|
|
||||||
end
|
|
||||||
|
|
||||||
def render
|
|
||||||
div.status_view do
|
|
||||||
div do
|
|
||||||
button.bright { "next" }.on(:click) { interpreter.tick }
|
|
||||||
" ".br
|
|
||||||
end
|
|
||||||
div do
|
|
||||||
h4 {"Status:"}
|
|
||||||
state.to_s.br
|
|
||||||
end
|
|
||||||
div do
|
|
||||||
h4 {"Stdout:"}
|
|
||||||
end
|
|
||||||
div do
|
|
||||||
interpreter.stdout.br
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
46
config.ru
46
config.ru
@ -1,42 +1,4 @@
|
|||||||
# config.ru
|
# Run via rack server
|
||||||
require 'bundler'
|
require 'bundler/setup'
|
||||||
Bundler.require
|
require 'volt/server'
|
||||||
|
run Volt::Server.new.app
|
||||||
Opal.use_gem "salama"
|
|
||||||
Opal.use_gem "salama-arm"
|
|
||||||
|
|
||||||
require "tilt/erb"
|
|
||||||
require "susy"
|
|
||||||
require "json"
|
|
||||||
require "react/source"
|
|
||||||
|
|
||||||
class DebugServer < Opal::Server
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
if env['PATH_INFO'].include? "/parse.json"
|
|
||||||
parse_out = parse(1).to_s
|
|
||||||
[200, { 'Content-Type' => 'text/json' }, [parse_out]]
|
|
||||||
else
|
|
||||||
super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
run DebugServer.new {|s|
|
|
||||||
s.append_path 'app'
|
|
||||||
s.append_path 'lib'
|
|
||||||
s.append_path File.dirname(::React::Source.bundled_path_for("react-with-addons.js"))
|
|
||||||
s.main = 'main'
|
|
||||||
s.debug = false
|
|
||||||
s.source_map = true
|
|
||||||
s.index_path = "index.html.erb"
|
|
||||||
}
|
|
||||||
|
136
config/app.rb
Normal file
136
config/app.rb
Normal 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
15
config/base/index.html
Normal 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
6
config/dependencies.rb
Normal 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")
|
10
config/initializers/boot.rb
Normal file
10
config/initializers/boot.rb
Normal 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.
|
2
config/initializers/server/salama.rb
Normal file
2
config/initializers/server/salama.rb
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Opal.use_gem "salama"
|
||||||
|
Opal.use_gem "salama-arm"
|
7
config/routes.rb
Normal file
7
config/routes.rb
Normal 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 '/', {}
|
@ -1,12 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Salama Debugger</title>
|
|
||||||
<link rel="stylesheet" href="/assets/styles.css">
|
|
||||||
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
|
|
||||||
<script src="/assets/react-with-addons.js"></script>
|
|
||||||
<%= javascript_include_tag 'main' %>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="content"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,37 +0,0 @@
|
|||||||
# A simple event registering/triggering module to mix into classes.
|
|
||||||
# Events are stored in the `@events` ivar.
|
|
||||||
module Eventable
|
|
||||||
|
|
||||||
# Register a handler for the given event name.
|
|
||||||
# The event name is the method name called on the handler object
|
|
||||||
#
|
|
||||||
# obj.on(:foo , some_object_that_implements foo( whateverargs)
|
|
||||||
#
|
|
||||||
# @param [String, Symbol] name event name
|
|
||||||
# @param [Object] object handling the event, ie implement the function name
|
|
||||||
# @return handler
|
|
||||||
def register_event(name, handler)
|
|
||||||
event_table[name] << handler
|
|
||||||
handler
|
|
||||||
end
|
|
||||||
|
|
||||||
def unregister_event(name, handler)
|
|
||||||
event_table[name].delete handler
|
|
||||||
end
|
|
||||||
|
|
||||||
def event_table
|
|
||||||
return @event_table if @event_table
|
|
||||||
@event_table = Hash.new { |hash, key| hash[key] = [] }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Trigger the given event name and passes all args to each handler
|
|
||||||
# for this event.
|
|
||||||
#
|
|
||||||
# obj.trigger(:foo)
|
|
||||||
# obj.trigger(:foo, 1, 2, 3)
|
|
||||||
#
|
|
||||||
# @param [String, Symbol] name event name to trigger
|
|
||||||
def trigger(name, *args)
|
|
||||||
event_table[name].each { |handler| handler.send( name.to_sym , *args) }
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,166 +0,0 @@
|
|||||||
|
|
||||||
require "eventable"
|
|
||||||
|
|
||||||
class Interpreter
|
|
||||||
# fire events for changed pc and register contents
|
|
||||||
include Eventable
|
|
||||||
|
|
||||||
# current instruction or pc
|
|
||||||
attr_reader :instruction
|
|
||||||
|
|
||||||
# an (arm style) link register. store the return address to return to
|
|
||||||
attr_reader :link
|
|
||||||
|
|
||||||
# current executing block. since this is not a hardware simulator this is luxury
|
|
||||||
attr_reader :block
|
|
||||||
|
|
||||||
# the registers, 12
|
|
||||||
attr_reader :registers
|
|
||||||
|
|
||||||
# collect the output
|
|
||||||
attr_reader :stdout
|
|
||||||
|
|
||||||
attr_reader :state
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@state = "runnnig"
|
|
||||||
@stdout = ""
|
|
||||||
@registers = {}
|
|
||||||
(0...16).each do |r|
|
|
||||||
set_register "r#{r}".to_sym , "r#{r}:unknown"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def start bl
|
|
||||||
set_block bl
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_block bl
|
|
||||||
return if @block == bl
|
|
||||||
raise "Error, nil block" unless bl
|
|
||||||
old = @block
|
|
||||||
@block = bl
|
|
||||||
trigger(:block_changed , old , bl)
|
|
||||||
set_instruction bl.codes.first
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_instruction i
|
|
||||||
@state = "exited" unless i
|
|
||||||
return if @instruction == i
|
|
||||||
old = @instruction
|
|
||||||
@instruction = i
|
|
||||||
trigger(:instruction_changed, old , i)
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_register( reg )
|
|
||||||
reg = reg.symbol if reg.is_a? Register::RegisterReference
|
|
||||||
raise "Not a register #{reg}" unless Register::RegisterReference.look_like_reg(reg)
|
|
||||||
@registers[reg]
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_register reg , val
|
|
||||||
old = get_register( reg ) # also ensures format
|
|
||||||
return if old === val
|
|
||||||
reg = reg.symbol if reg.is_a? Register::RegisterReference
|
|
||||||
@registers[reg] = val
|
|
||||||
trigger(:register_changed, reg , old , val)
|
|
||||||
end
|
|
||||||
|
|
||||||
def tick
|
|
||||||
return unless @instruction
|
|
||||||
name = @instruction.class.name.split("::").last
|
|
||||||
fetch = send "execute_#{name}"
|
|
||||||
return unless fetch
|
|
||||||
fetch_next_intruction
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_next_intruction
|
|
||||||
if(@instruction != @block.codes.last)
|
|
||||||
set_instruction @block.codes[ @block.codes.index(@instruction) + 1]
|
|
||||||
else
|
|
||||||
next_b = @block.method.source.blocks.index(@block) + 1
|
|
||||||
set_block @block.method.source.blocks[next_b]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def object_for reg
|
|
||||||
id = get_register(reg)
|
|
||||||
Virtual.machine.objects[id]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Instruction interpretation starts here
|
|
||||||
def execute_Branch
|
|
||||||
target = @instruction.block
|
|
||||||
set_block target
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_LoadConstant
|
|
||||||
to = @instruction.register
|
|
||||||
value = @instruction.constant.object_id
|
|
||||||
set_register( to , value )
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_GetSlot
|
|
||||||
object = object_for( @instruction.array )
|
|
||||||
value = object.internal_object_get( @instruction.index )
|
|
||||||
value = value.object_id unless value.is_a? Integer
|
|
||||||
set_register( @instruction.register , value )
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_SetSlot
|
|
||||||
value = object_for( @instruction.register )
|
|
||||||
object = object_for( @instruction.array )
|
|
||||||
object.internal_object_set( @instruction.index , value )
|
|
||||||
trigger(:object_changed, @instruction.register )
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_RegisterTransfer
|
|
||||||
value = get_register @instruction.from
|
|
||||||
set_register @instruction.to , value
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_FunctionCall
|
|
||||||
@link = [@block , @instruction]
|
|
||||||
next_block = @instruction.method.source.blocks.first
|
|
||||||
set_block next_block
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_SaveReturn
|
|
||||||
object = object_for @instruction.register
|
|
||||||
raise "save return has nothing to save" unless @link
|
|
||||||
trigger(:object_changed, @instruction.register )
|
|
||||||
object.internal_object_set @instruction.index , @link
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_Syscall
|
|
||||||
name = @instruction.name
|
|
||||||
case name
|
|
||||||
when :putstring
|
|
||||||
str = object_for( :r1 ) # should test length, ie r2
|
|
||||||
raise "NO string for putstring #{str}" unless str.is_a? Symbol
|
|
||||||
@stdout += str.to_s
|
|
||||||
when :exit
|
|
||||||
set_instruction(nil)
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
raise "un-implemented syscall #{name}"
|
|
||||||
end
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def execute_FunctionReturn
|
|
||||||
object = object_for( @instruction.register )
|
|
||||||
#wouldn't need to assign to link, but makes tsting easier
|
|
||||||
@link = object.internal_object_get( @instruction.index )
|
|
||||||
@block , @instruction = @link
|
|
||||||
# we jump back to the call instruction. so it is as if the call never happened and we continue
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
5
spec/app/main/integration/blocks_spec.rb
Normal file
5
spec/app/main/integration/blocks_spec.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe '', type: :feature do
|
||||||
|
# Specs here
|
||||||
|
end
|
5
spec/app/main/integration/classes_spec.rb
Normal file
5
spec/app/main/integration/classes_spec.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe '', type: :feature do
|
||||||
|
# Specs here
|
||||||
|
end
|
5
spec/app/main/integration/objects_spec.rb
Normal file
5
spec/app/main/integration/objects_spec.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe '', type: :feature do
|
||||||
|
# Specs here
|
||||||
|
end
|
5
spec/app/main/integration/registers_spec.rb
Normal file
5
spec/app/main/integration/registers_spec.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe '', type: :feature do
|
||||||
|
# Specs here
|
||||||
|
end
|
5
spec/app/main/integration/sources_spec.rb
Normal file
5
spec/app/main/integration/sources_spec.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe '', type: :feature do
|
||||||
|
# Specs here
|
||||||
|
end
|
5
spec/app/main/integration/statuses_spec.rb
Normal file
5
spec/app/main/integration/statuses_spec.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe '', type: :feature do
|
||||||
|
# Specs here
|
||||||
|
end
|
307
static/hint.css
307
static/hint.css
@ -1,307 +0,0 @@
|
|||||||
/*! Hint.css - v1.3.5 - 2015-06-16
|
|
||||||
* http://kushagragour.in/lab/hint/
|
|
||||||
* Copyright (c) 2015 Kushagra Gour; Licensed MIT */
|
|
||||||
|
|
||||||
/*-------------------------------------*\
|
|
||||||
HINT.css - A CSS tooltip library
|
|
||||||
\*-------------------------------------*/
|
|
||||||
/**
|
|
||||||
* HINT.css is a tooltip library made in pure CSS.
|
|
||||||
*
|
|
||||||
* Source: https://github.com/chinchang/hint.css
|
|
||||||
* Demo: http://kushagragour.in/lab/hint/
|
|
||||||
*
|
|
||||||
* Release under The MIT License
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* source: hint-core.scss
|
|
||||||
*
|
|
||||||
* Defines the basic styling for the tooltip.
|
|
||||||
* Each tooltip is made of 2 parts:
|
|
||||||
* 1) body (:after)
|
|
||||||
* 2) arrow (:before)
|
|
||||||
*
|
|
||||||
* Classes added:
|
|
||||||
* 1) hint
|
|
||||||
*/
|
|
||||||
.hint, [data-hint] {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
/**
|
|
||||||
* tooltip arrow
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* tooltip body
|
|
||||||
*/ }
|
|
||||||
.hint:before, .hint:after, [data-hint]:before, [data-hint]:after {
|
|
||||||
position: absolute;
|
|
||||||
-webkit-transform: translate3d(0, 0, 0);
|
|
||||||
-moz-transform: translate3d(0, 0, 0);
|
|
||||||
transform: translate3d(0, 0, 0);
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
z-index: 1000000;
|
|
||||||
pointer-events: none;
|
|
||||||
-webkit-transition: 0.3s ease;
|
|
||||||
-moz-transition: 0.3s ease;
|
|
||||||
transition: 0.3s ease;
|
|
||||||
-webkit-transition-delay: 0ms;
|
|
||||||
-moz-transition-delay: 0ms;
|
|
||||||
transition-delay: 0ms; }
|
|
||||||
.hint:hover:before, .hint:hover:after, .hint:focus:before, .hint:focus:after, [data-hint]:hover:before, [data-hint]:hover:after, [data-hint]:focus:before, [data-hint]:focus:after {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1; }
|
|
||||||
.hint:hover:before, .hint:hover:after, [data-hint]:hover:before, [data-hint]:hover:after {
|
|
||||||
-webkit-transition-delay: 100ms;
|
|
||||||
-moz-transition-delay: 100ms;
|
|
||||||
transition-delay: 100ms; }
|
|
||||||
.hint:before, [data-hint]:before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
background: transparent;
|
|
||||||
border: 6px solid transparent;
|
|
||||||
z-index: 1000001; }
|
|
||||||
.hint:after, [data-hint]:after {
|
|
||||||
content: attr(data-hint);
|
|
||||||
background: #383838;
|
|
||||||
color: white;
|
|
||||||
padding: 8px 10px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 12px;
|
|
||||||
white-space: nowrap; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* source: hint-position.scss
|
|
||||||
*
|
|
||||||
* Defines the positoning logic for the tooltips.
|
|
||||||
*
|
|
||||||
* Classes added:
|
|
||||||
* 1) hint--top
|
|
||||||
* 2) hint--bottom
|
|
||||||
* 3) hint--left
|
|
||||||
* 4) hint--right
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* set default color for tooltip arrows
|
|
||||||
*/
|
|
||||||
.hint--top:before {
|
|
||||||
border-top-color: #383838; }
|
|
||||||
|
|
||||||
.hint--bottom:before {
|
|
||||||
border-bottom-color: #383838; }
|
|
||||||
|
|
||||||
.hint--left:before {
|
|
||||||
border-left-color: #383838; }
|
|
||||||
|
|
||||||
.hint--right:before {
|
|
||||||
border-right-color: #383838; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* top tooltip
|
|
||||||
*/
|
|
||||||
.hint--top:before {
|
|
||||||
margin-bottom: -12px; }
|
|
||||||
.hint--top:after {
|
|
||||||
margin-left: -18px; }
|
|
||||||
.hint--top:before, .hint--top:after {
|
|
||||||
bottom: 100%;
|
|
||||||
left: 50%; }
|
|
||||||
.hint--top:hover:after, .hint--top:hover:before, .hint--top:focus:after, .hint--top:focus:before {
|
|
||||||
-webkit-transform: translateY(-8px);
|
|
||||||
-moz-transform: translateY(-8px);
|
|
||||||
transform: translateY(-8px); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bottom tooltip
|
|
||||||
*/
|
|
||||||
.hint--bottom:before {
|
|
||||||
margin-top: -12px; }
|
|
||||||
.hint--bottom:after {
|
|
||||||
margin-left: -18px; }
|
|
||||||
.hint--bottom:before, .hint--bottom:after {
|
|
||||||
top: 100%;
|
|
||||||
left: 50%; }
|
|
||||||
.hint--bottom:hover:after, .hint--bottom:hover:before, .hint--bottom:focus:after, .hint--bottom:focus:before {
|
|
||||||
-webkit-transform: translateY(8px);
|
|
||||||
-moz-transform: translateY(8px);
|
|
||||||
transform: translateY(8px); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* right tooltip
|
|
||||||
*/
|
|
||||||
.hint--right:before {
|
|
||||||
margin-left: -12px;
|
|
||||||
margin-bottom: -6px; }
|
|
||||||
.hint--right:after {
|
|
||||||
margin-bottom: -14px; }
|
|
||||||
.hint--right:before, .hint--right:after {
|
|
||||||
left: 100%;
|
|
||||||
bottom: 50%; }
|
|
||||||
.hint--right:hover:after, .hint--right:hover:before, .hint--right:focus:after, .hint--right:focus:before {
|
|
||||||
-webkit-transform: translateX(8px);
|
|
||||||
-moz-transform: translateX(8px);
|
|
||||||
transform: translateX(8px); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* left tooltip
|
|
||||||
*/
|
|
||||||
.hint--left:before {
|
|
||||||
margin-right: -12px;
|
|
||||||
margin-bottom: -6px; }
|
|
||||||
.hint--left:after {
|
|
||||||
margin-bottom: -14px; }
|
|
||||||
.hint--left:before, .hint--left:after {
|
|
||||||
right: 100%;
|
|
||||||
bottom: 50%; }
|
|
||||||
.hint--left:hover:after, .hint--left:hover:before, .hint--left:focus:after, .hint--left:focus:before {
|
|
||||||
-webkit-transform: translateX(-8px);
|
|
||||||
-moz-transform: translateX(-8px);
|
|
||||||
transform: translateX(-8px); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* source: hint-theme.scss
|
|
||||||
*
|
|
||||||
* Defines basic theme for tooltips.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
.hint, [data-hint] {
|
|
||||||
/**
|
|
||||||
* tooltip body
|
|
||||||
*/ }
|
|
||||||
.hint:after, [data-hint]:after {
|
|
||||||
text-shadow: 0 -1px 0px black;
|
|
||||||
box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.3); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* source: hint-color-types.scss
|
|
||||||
*
|
|
||||||
* Contains tooltips of various types based on color differences.
|
|
||||||
*
|
|
||||||
* Classes added:
|
|
||||||
* 1) hint--error
|
|
||||||
* 2) hint--warning
|
|
||||||
* 3) hint--info
|
|
||||||
* 4) hint--success
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Error
|
|
||||||
*/
|
|
||||||
.hint--error:after {
|
|
||||||
background-color: #b34e4d;
|
|
||||||
text-shadow: 0 -1px 0px #592726; }
|
|
||||||
.hint--error.hint--top:before {
|
|
||||||
border-top-color: #b34e4d; }
|
|
||||||
.hint--error.hint--bottom:before {
|
|
||||||
border-bottom-color: #b34e4d; }
|
|
||||||
.hint--error.hint--left:before {
|
|
||||||
border-left-color: #b34e4d; }
|
|
||||||
.hint--error.hint--right:before {
|
|
||||||
border-right-color: #b34e4d; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Warning
|
|
||||||
*/
|
|
||||||
.hint--warning:after {
|
|
||||||
background-color: #c09854;
|
|
||||||
text-shadow: 0 -1px 0px #6c5328; }
|
|
||||||
.hint--warning.hint--top:before {
|
|
||||||
border-top-color: #c09854; }
|
|
||||||
.hint--warning.hint--bottom:before {
|
|
||||||
border-bottom-color: #c09854; }
|
|
||||||
.hint--warning.hint--left:before {
|
|
||||||
border-left-color: #c09854; }
|
|
||||||
.hint--warning.hint--right:before {
|
|
||||||
border-right-color: #c09854; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Info
|
|
||||||
*/
|
|
||||||
.hint--info:after {
|
|
||||||
background-color: #3986ac;
|
|
||||||
text-shadow: 0 -1px 0px #193b4d; }
|
|
||||||
.hint--info.hint--top:before {
|
|
||||||
border-top-color: #3986ac; }
|
|
||||||
.hint--info.hint--bottom:before {
|
|
||||||
border-bottom-color: #3986ac; }
|
|
||||||
.hint--info.hint--left:before {
|
|
||||||
border-left-color: #3986ac; }
|
|
||||||
.hint--info.hint--right:before {
|
|
||||||
border-right-color: #3986ac; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Success
|
|
||||||
*/
|
|
||||||
.hint--success:after {
|
|
||||||
background-color: #458746;
|
|
||||||
text-shadow: 0 -1px 0px #1a321a; }
|
|
||||||
.hint--success.hint--top:before {
|
|
||||||
border-top-color: #458746; }
|
|
||||||
.hint--success.hint--bottom:before {
|
|
||||||
border-bottom-color: #458746; }
|
|
||||||
.hint--success.hint--left:before {
|
|
||||||
border-left-color: #458746; }
|
|
||||||
.hint--success.hint--right:before {
|
|
||||||
border-right-color: #458746; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* source: hint-always.scss
|
|
||||||
*
|
|
||||||
* Defines a persisted tooltip which shows always.
|
|
||||||
*
|
|
||||||
* Classes added:
|
|
||||||
* 1) hint--always
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
.hint--always:after, .hint--always:before {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible; }
|
|
||||||
.hint--always.hint--top:after, .hint--always.hint--top:before {
|
|
||||||
-webkit-transform: translateY(-8px);
|
|
||||||
-moz-transform: translateY(-8px);
|
|
||||||
transform: translateY(-8px); }
|
|
||||||
.hint--always.hint--bottom:after, .hint--always.hint--bottom:before {
|
|
||||||
-webkit-transform: translateY(8px);
|
|
||||||
-moz-transform: translateY(8px);
|
|
||||||
transform: translateY(8px); }
|
|
||||||
.hint--always.hint--left:after, .hint--always.hint--left:before {
|
|
||||||
-webkit-transform: translateX(-8px);
|
|
||||||
-moz-transform: translateX(-8px);
|
|
||||||
transform: translateX(-8px); }
|
|
||||||
.hint--always.hint--right:after, .hint--always.hint--right:before {
|
|
||||||
-webkit-transform: translateX(8px);
|
|
||||||
-moz-transform: translateX(8px);
|
|
||||||
transform: translateX(8px); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* source: hint-rounded.scss
|
|
||||||
*
|
|
||||||
* Defines rounded corner tooltips.
|
|
||||||
*
|
|
||||||
* Classes added:
|
|
||||||
* 1) hint--rounded
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
.hint--rounded:after {
|
|
||||||
border-radius: 4px; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* source: hint-effects.scss
|
|
||||||
*
|
|
||||||
* Defines various transition effects for the tooltips.
|
|
||||||
*
|
|
||||||
* Classes added:
|
|
||||||
* 1) hint--no-animate
|
|
||||||
* 2) hint--bounce
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
.hint--no-animate:before, .hint--no-animate:after {
|
|
||||||
-webkit-transition-duration: 0ms;
|
|
||||||
-moz-transition-duration: 0ms;
|
|
||||||
transition-duration: 0ms; }
|
|
||||||
|
|
||||||
.hint--bounce:before, .hint--bounce:after {
|
|
||||||
-webkit-transition: opacity 0.3s ease, visibility 0.3s ease, -webkit-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);
|
|
||||||
-moz-transition: opacity 0.3s ease, visibility 0.3s ease, -moz-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);
|
|
||||||
transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24); }
|
|
@ -1,21 +0,0 @@
|
|||||||
require 'rubygems'
|
|
||||||
require 'bundler'
|
|
||||||
begin
|
|
||||||
Bundler.setup(:default, :development)
|
|
||||||
rescue Bundler::BundlerError => e
|
|
||||||
$stderr.puts e.message
|
|
||||||
$stderr.puts "Run `bundle install` to install missing gems"
|
|
||||||
exit e.status_code
|
|
||||||
end
|
|
||||||
if ENV['CODECLIMATE_REPO_TOKEN']
|
|
||||||
require "codeclimate-test-reporter"
|
|
||||||
CodeClimate::TestReporter.start
|
|
||||||
end
|
|
||||||
|
|
||||||
require "minitest/autorun"
|
|
||||||
|
|
||||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
||||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test'))
|
|
||||||
|
|
||||||
require "salama"
|
|
||||||
require "interpreter"
|
|
@ -1,82 +0,0 @@
|
|||||||
require_relative "helper"
|
|
||||||
|
|
||||||
class InterpreterTest < MiniTest::Test
|
|
||||||
|
|
||||||
def setup
|
|
||||||
Virtual.machine.boot
|
|
||||||
code = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:putstring, [] ,Ast::StringExpression.new("Hello again"))])
|
|
||||||
Virtual::Compiler.compile( code , Virtual.machine.space.get_main )
|
|
||||||
Virtual.machine.run_before "Register::CallImplementation"
|
|
||||||
@interpreter = Interpreter.new
|
|
||||||
@interpreter.start Virtual.machine.init
|
|
||||||
end
|
|
||||||
|
|
||||||
def ticks num
|
|
||||||
last = nil
|
|
||||||
num.times do
|
|
||||||
last = @interpreter.instruction
|
|
||||||
@interpreter.tick
|
|
||||||
end
|
|
||||||
return last
|
|
||||||
end
|
|
||||||
def test_branch
|
|
||||||
was = @interpreter.block
|
|
||||||
assert_equal Register::Branch , ticks(1).class
|
|
||||||
assert was != @interpreter.block
|
|
||||||
end
|
|
||||||
def test_load
|
|
||||||
assert_equal Register::LoadConstant , ticks(2).class
|
|
||||||
assert_equal Parfait::Space , Virtual.machine.objects[ @interpreter.get_register(:r1)].class
|
|
||||||
assert_equal :r1, @interpreter.instruction.array.symbol
|
|
||||||
end
|
|
||||||
def test_get
|
|
||||||
assert_equal Register::GetSlot , ticks(3).class
|
|
||||||
assert @interpreter.get_register( :r3 )
|
|
||||||
assert @interpreter.get_register( :r3 ).is_a? Integer
|
|
||||||
end
|
|
||||||
def test_transfer
|
|
||||||
transfer = ticks 5
|
|
||||||
assert_equal Register::RegisterTransfer , transfer.class
|
|
||||||
assert_equal @interpreter.get_register(transfer.to) , @interpreter.get_register(transfer.from)
|
|
||||||
end
|
|
||||||
def test_call
|
|
||||||
assert_equal Register::FunctionCall , ticks(7).class
|
|
||||||
assert @interpreter.link
|
|
||||||
end
|
|
||||||
def test_save
|
|
||||||
done = ticks(8)
|
|
||||||
assert_equal Register::SaveReturn , done.class
|
|
||||||
assert @interpreter.get_register done.register.symbol
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_chain
|
|
||||||
["Branch" , "LoadConstant" , "GetSlot" , "SetSlot" , "RegisterTransfer" ,
|
|
||||||
"GetSlot" , "FunctionCall" , "SaveReturn" , "LoadConstant" , "SetSlot" ,
|
|
||||||
"GetSlot" , "GetSlot" , "SetSlot" , "LoadConstant" , "SetSlot" ,
|
|
||||||
"RegisterTransfer" , "GetSlot" , "FunctionCall" , "SaveReturn" , "RegisterTransfer" ,
|
|
||||||
"Syscall" , "RegisterTransfer" , "RegisterTransfer" , "SetSlot" , "GetSlot" ,
|
|
||||||
"GetSlot" , "RegisterTransfer" ,"GetSlot" , "GetSlot","GetSlot",
|
|
||||||
"FunctionReturn" , "RegisterTransfer" , "Syscall" , "NilClass"].each_with_index do |name , index|
|
|
||||||
got = ticks(1)
|
|
||||||
assert got.class.name.index(name) , "Wrong class for #{index+1}, expect #{name} , got #{got}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_putstring
|
|
||||||
done = ticks(21)
|
|
||||||
assert_equal Register::Syscall , done.class
|
|
||||||
assert_equal "Hello again" , @interpreter.stdout
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_return
|
|
||||||
done = ticks(31)
|
|
||||||
assert_equal Register::FunctionReturn , done.class
|
|
||||||
assert @interpreter.block.is_a?(Virtual::Block)
|
|
||||||
assert @interpreter.instruction.is_a?(Register::Instruction) , "not instruction #{@interpreter.instruction}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_exit
|
|
||||||
done = ticks(34)
|
|
||||||
assert_equal NilClass , done.class
|
|
||||||
end
|
|
||||||
end
|
|
Reference in New Issue
Block a user