fOOrth 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rdoc_options +17 -0
- data/Gemfile +4 -0
- data/README.md +67 -0
- data/bin/fOOrth +8 -0
- data/demo.rb +24 -0
- data/fOOrth.gemspec +40 -0
- data/fOOrth.reek +109 -0
- data/integration/README.md +12 -0
- data/integration/_FILE_test.foorth +5 -0
- data/integration/array_lib_tests.rb +360 -0
- data/integration/class_lib_tests.rb +116 -0
- data/integration/clone_lib_tests.rb +108 -0
- data/integration/comparison_tests.rb +132 -0
- data/integration/compile_lib_tests.rb +190 -0
- data/integration/ctrl_struct_lib_tests.rb +80 -0
- data/integration/data_ref_lib_tests.rb +43 -0
- data/integration/exception_lib_tests.rb +86 -0
- data/integration/fiber_bundle_tests.rb +380 -0
- data/integration/hash_lib_tests.rb +120 -0
- data/integration/in_stream_test_1.txt +4 -0
- data/integration/load_test_one.foorth +6 -0
- data/integration/load_test_two.foorth +4 -0
- data/integration/numeric_lib_tests.rb +321 -0
- data/integration/object_lib_tests.rb +38 -0
- data/integration/procedure_lib_tests.rb +40 -0
- data/integration/queue_lib_tests.rb +66 -0
- data/integration/stack_lib_tests.rb +70 -0
- data/integration/standard_lib_tests.rb +208 -0
- data/integration/stdio_lib_tests.rb +52 -0
- data/integration/stream_lib_tests.rb +196 -0
- data/integration/string_lib_tests.rb +217 -0
- data/integration/support/foorth_testing.rb +135 -0
- data/integration/thread_lib_tests.rb +83 -0
- data/integration/time_lib_tests.rb +791 -0
- data/integration/vm_lib_tests.rb +38 -0
- data/lib/fOOrth.rb +57 -0
- data/lib/fOOrth/compiler.rb +78 -0
- data/lib/fOOrth/compiler/context.rb +49 -0
- data/lib/fOOrth/compiler/context/locals.rb +34 -0
- data/lib/fOOrth/compiler/context/map_name.rb +92 -0
- data/lib/fOOrth/compiler/context/tags.rb +48 -0
- data/lib/fOOrth/compiler/modes.rb +32 -0
- data/lib/fOOrth/compiler/modes/compiled.rb +41 -0
- data/lib/fOOrth/compiler/modes/deferred.rb +57 -0
- data/lib/fOOrth/compiler/modes/delayed.rb +40 -0
- data/lib/fOOrth/compiler/modes/nested.rb +34 -0
- data/lib/fOOrth/compiler/modes/suspend.rb +32 -0
- data/lib/fOOrth/compiler/parser.rb +26 -0
- data/lib/fOOrth/compiler/parser/get_string.rb +71 -0
- data/lib/fOOrth/compiler/parser/normal.rb +53 -0
- data/lib/fOOrth/compiler/parser/skip.rb +50 -0
- data/lib/fOOrth/compiler/parser/special.rb +42 -0
- data/lib/fOOrth/compiler/process.rb +47 -0
- data/lib/fOOrth/compiler/process/generate.rb +24 -0
- data/lib/fOOrth/compiler/process/get_token.rb +23 -0
- data/lib/fOOrth/compiler/process/procedure.rb +55 -0
- data/lib/fOOrth/compiler/process/string.rb +20 -0
- data/lib/fOOrth/compiler/source.rb +51 -0
- data/lib/fOOrth/compiler/source/console.rb +70 -0
- data/lib/fOOrth/compiler/source/file_source.rb +37 -0
- data/lib/fOOrth/compiler/source/read_point.rb +46 -0
- data/lib/fOOrth/compiler/source/string_source.rb +28 -0
- data/lib/fOOrth/compiler/token.rb +37 -0
- data/lib/fOOrth/compiler/word_specs.rb +178 -0
- data/lib/fOOrth/core.rb +27 -0
- data/lib/fOOrth/core/class.rb +116 -0
- data/lib/fOOrth/core/object.rb +78 -0
- data/lib/fOOrth/core/virtual_machine.rb +28 -0
- data/lib/fOOrth/debug.rb +13 -0
- data/lib/fOOrth/debug/context_dump.rb +31 -0
- data/lib/fOOrth/debug/dbg_puts.rb +17 -0
- data/lib/fOOrth/debug/display_abort.rb +37 -0
- data/lib/fOOrth/debug/vm_dump.rb +27 -0
- data/lib/fOOrth/initialize.rb +83 -0
- data/lib/fOOrth/interpreter.rb +24 -0
- data/lib/fOOrth/interpreter/add_to_hash.rb +17 -0
- data/lib/fOOrth/interpreter/data_stack.rb +125 -0
- data/lib/fOOrth/interpreter/do_loop.rb +55 -0
- data/lib/fOOrth/interpreter/squash.rb +25 -0
- data/lib/fOOrth/library.rb +38 -0
- data/lib/fOOrth/library/array_library.rb +577 -0
- data/lib/fOOrth/library/bundle_library.rb +112 -0
- data/lib/fOOrth/library/class_library.rb +90 -0
- data/lib/fOOrth/library/clone_library.rb +72 -0
- data/lib/fOOrth/library/command_library.rb +205 -0
- data/lib/fOOrth/library/compile_library.rb +181 -0
- data/lib/fOOrth/library/complex_library.rb +81 -0
- data/lib/fOOrth/library/ctrl_struct_library.rb +116 -0
- data/lib/fOOrth/library/data_ref_library.rb +100 -0
- data/lib/fOOrth/library/duration/arithmetic.rb +114 -0
- data/lib/fOOrth/library/duration/formatter.rb +152 -0
- data/lib/fOOrth/library/duration/intervals.rb +233 -0
- data/lib/fOOrth/library/duration/make.rb +75 -0
- data/lib/fOOrth/library/duration_library.rb +52 -0
- data/lib/fOOrth/library/fiber_library.rb +120 -0
- data/lib/fOOrth/library/hash_library.rb +203 -0
- data/lib/fOOrth/library/in_stream_library.rb +81 -0
- data/lib/fOOrth/library/integer_library.rb +104 -0
- data/lib/fOOrth/library/mutex_library.rb +31 -0
- data/lib/fOOrth/library/numeric_library.rb +380 -0
- data/lib/fOOrth/library/object_library.rb +80 -0
- data/lib/fOOrth/library/other_value_types_library.rb +96 -0
- data/lib/fOOrth/library/out_stream_library.rb +146 -0
- data/lib/fOOrth/library/procedure_library.rb +65 -0
- data/lib/fOOrth/library/queue_library.rb +47 -0
- data/lib/fOOrth/library/rational_library.rb +90 -0
- data/lib/fOOrth/library/stack_library.rb +56 -0
- data/lib/fOOrth/library/stdio_library.rb +56 -0
- data/lib/fOOrth/library/string_library.rb +285 -0
- data/lib/fOOrth/library/stubs.rb +76 -0
- data/lib/fOOrth/library/sync_bundle_library.rb +50 -0
- data/lib/fOOrth/library/thread_library.rb +73 -0
- data/lib/fOOrth/library/time_library.rb +302 -0
- data/lib/fOOrth/library/vm_library.rb +105 -0
- data/lib/fOOrth/main.rb +125 -0
- data/lib/fOOrth/monkey_patch.rb +14 -0
- data/lib/fOOrth/monkey_patch/complex.rb +30 -0
- data/lib/fOOrth/monkey_patch/exceptions.rb +154 -0
- data/lib/fOOrth/monkey_patch/false.rb +11 -0
- data/lib/fOOrth/monkey_patch/float.rb +22 -0
- data/lib/fOOrth/monkey_patch/integer.rb +22 -0
- data/lib/fOOrth/monkey_patch/nil.rb +11 -0
- data/lib/fOOrth/monkey_patch/numeric.rb +33 -0
- data/lib/fOOrth/monkey_patch/object.rb +43 -0
- data/lib/fOOrth/monkey_patch/rational.rb +31 -0
- data/lib/fOOrth/monkey_patch/string.rb +51 -0
- data/lib/fOOrth/symbol_map.rb +82 -0
- data/lib/fOOrth/version.rb +7 -0
- data/license.txt +21 -0
- data/rakefile.rb +65 -0
- data/reek.txt +1 -0
- data/sire.rb +132 -0
- data/t.txt +3 -0
- data/test.foorth +5 -0
- data/tests/compiler/context_tests.rb +180 -0
- data/tests/compiler/file_source_test_one.txt +1 -0
- data/tests/compiler/file_source_test_three.txt +3 -0
- data/tests/compiler/file_source_test_two.txt +3 -0
- data/tests/compiler/file_source_tests.rb +130 -0
- data/tests/compiler/mode_tests.rb +45 -0
- data/tests/compiler/parser_tests.rb +116 -0
- data/tests/compiler/spec_tests.rb +113 -0
- data/tests/compiler/string_source_tests.rb +128 -0
- data/tests/core_tests.rb +138 -0
- data/tests/interpreter/data_stack_tests.rb +119 -0
- data/tests/monkey_patch/coerce_test.rb +131 -0
- data/tests/monkey_patch/complex_test.rb +25 -0
- data/tests/monkey_patch/numeric_test.rb +62 -0
- data/tests/monkey_patch/object_test.rb +49 -0
- data/tests/monkey_patch/rational_test.rb +57 -0
- data/tests/monkey_patch/string_test.rb +53 -0
- data/tests/symbol_map_tests.rb +53 -0
- metadata +366 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
#Extensions to the \Rational class required by the fOOrth language system.
|
|
4
|
+
class Rational
|
|
5
|
+
#Convert this rational number to a form suitable for embedding in a source string.
|
|
6
|
+
#<br>Returns
|
|
7
|
+
#* An embeddable form of this rational number as a string.
|
|
8
|
+
def foorth_embed
|
|
9
|
+
"'#{self.to_s}'.to_r"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
#Convert this object to a rational. Returns self.
|
|
13
|
+
def to_foorth_r
|
|
14
|
+
self
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
#Argument coercion methods.
|
|
18
|
+
|
|
19
|
+
#Coerce the argument to match my type.
|
|
20
|
+
def self.foorth_coerce(arg)
|
|
21
|
+
arg.to_foorth_r || (error "F40: Cannot coerce a #{arg.foorth_name} to a Rational")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#Coerce the argument to match my type.
|
|
25
|
+
#<br>Endemic Code Smells
|
|
26
|
+
#* :reek:FeatureEnvy -- false positive
|
|
27
|
+
def foorth_coerce(arg)
|
|
28
|
+
arg.to_foorth_r || (error "F40: Cannot coerce a #{arg.foorth_name} to a Rational")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
#Extensions to the \String class required by the fOOrth language system.
|
|
4
|
+
class String
|
|
5
|
+
#Convert this String to a form suitable for embedding in a source string.
|
|
6
|
+
#<br>Returns
|
|
7
|
+
#* An embeddable form of this string as a string.
|
|
8
|
+
def foorth_embed
|
|
9
|
+
self.inspect
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
#Coerce the argument to match my type.
|
|
13
|
+
#<br>Endemic Code Smells
|
|
14
|
+
#* :reek:FeatureEnvy -- false positive
|
|
15
|
+
def foorth_coerce(arg)
|
|
16
|
+
arg.to_s
|
|
17
|
+
rescue
|
|
18
|
+
error "F40: Cannot coerce a #{arg.foorth_name} to an String instance"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
#Convert this string to a single character string.
|
|
22
|
+
def to_foorth_c
|
|
23
|
+
self[0]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
#Convert this string to a numeric. Return a number or nil on fail.
|
|
27
|
+
def to_foorth_n
|
|
28
|
+
if /\di$/ =~ self #Check for a trailing '<digit>i'.
|
|
29
|
+
#Check for the internal '+' or '-'sign.
|
|
30
|
+
if /(?<=\d)[+-]/ =~ self
|
|
31
|
+
Complex(($PREMATCH).to_foorth_n, ($MATCH + $POSTMATCH).chop.to_foorth_n)
|
|
32
|
+
else
|
|
33
|
+
Complex(0, self.chop.to_foorth_n)
|
|
34
|
+
end
|
|
35
|
+
elsif /\d\/\d/ =~ self #Check for an embedded '<digit>/<digit>'.
|
|
36
|
+
Rational(self)
|
|
37
|
+
elsif /\d\.\d/ =~ self #Check for an embedded '<digit>.<digit>'.
|
|
38
|
+
Float(self)
|
|
39
|
+
else #For the rest, assume an integer.
|
|
40
|
+
Integer(self)
|
|
41
|
+
end
|
|
42
|
+
rescue
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
#Convert this string to a rational. Return a number or nil on fail.
|
|
47
|
+
def to_foorth_r
|
|
48
|
+
self.to_foorth_n.to_foorth_r
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
#* symbol_map.rb - The name mangler for the foorth Language System.
|
|
4
|
+
module XfOOrth
|
|
5
|
+
|
|
6
|
+
#A module used to map strings to unique symbols
|
|
7
|
+
module SymbolMap
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
#Access to the mapping of names to symbols.
|
|
11
|
+
attr_reader :forward_map
|
|
12
|
+
|
|
13
|
+
#Access to the mapping of symbols to names.
|
|
14
|
+
attr_reader :reverse_map
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
@sync = Mutex.new
|
|
18
|
+
@incrementer = '_000'
|
|
19
|
+
@forward_map = Hash.new
|
|
20
|
+
@reverse_map = Hash.new
|
|
21
|
+
|
|
22
|
+
#Add a global mapping for a string to a symbol that will not collide with
|
|
23
|
+
#existing symbols.
|
|
24
|
+
#<br>Parameters:
|
|
25
|
+
#* name - The string to be mapped.
|
|
26
|
+
#* presym - A pre-assigned symbol value or nil to generate a symbol.
|
|
27
|
+
#<br>Returns:
|
|
28
|
+
#* The symbol that corresponds to the name.
|
|
29
|
+
#<br>Endemic Code Smells
|
|
30
|
+
#* :reek:ControlParameter -- false positive
|
|
31
|
+
def self.add_entry(name, presym=nil)
|
|
32
|
+
@sync.synchronize do
|
|
33
|
+
unless (symbol = @forward_map[name])
|
|
34
|
+
symbol = presym || (@incrementer.succ!).to_sym
|
|
35
|
+
connect(name, symbol)
|
|
36
|
+
else
|
|
37
|
+
error "F90: Attempt to redefine #{name}." if presym && presym != symbol
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
symbol
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
#Get the entry for the mapping string. Return nil if there is no entry.
|
|
45
|
+
#<br>Parameters:
|
|
46
|
+
#* name - The string to be looked up.
|
|
47
|
+
#<br>Returns:
|
|
48
|
+
#* A symbol or nil if the symbol is not in the map.
|
|
49
|
+
def self.map(name)
|
|
50
|
+
@forward_map[name]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
#Get the entry for the mapping symbol. Return nil if there is no entry.
|
|
54
|
+
#<br>Parameters:
|
|
55
|
+
#* mapped - The mapping of the desired symbol.
|
|
56
|
+
#<br>Returns:
|
|
57
|
+
#* The name or nil if the symbol is not in the map.
|
|
58
|
+
def self.unmap(mapped)
|
|
59
|
+
@reverse_map[mapped]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#Reset the incrementer to the given string. This used for testing only.
|
|
63
|
+
#<br>Parameters:
|
|
64
|
+
#* start - The new starting point of the generated symbols.
|
|
65
|
+
#<br>Note:
|
|
66
|
+
#* FOR TESTING ONLY.
|
|
67
|
+
def self.restart(start)
|
|
68
|
+
@incrementer = start
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#Set up the internal workings of the mapping hashes.
|
|
72
|
+
private
|
|
73
|
+
def self.connect(name, symbol)
|
|
74
|
+
if (old = @reverse_map[symbol]) && (old != name)
|
|
75
|
+
error "F90: Attempt to redefine #{name}."
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
@reverse_map[symbol] = name
|
|
79
|
+
@forward_map[name] = symbol
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
data/license.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
=== The MIT License (MIT).
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Peter Camilleri
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/rakefile.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
|
|
4
|
+
require 'rake/testtask'
|
|
5
|
+
require 'rdoc/task'
|
|
6
|
+
require "bundler/gem_tasks"
|
|
7
|
+
|
|
8
|
+
#Generate internal documentation with rdoc.
|
|
9
|
+
RDoc::Task.new do |rdoc|
|
|
10
|
+
rdoc.rdoc_dir = "rdoc"
|
|
11
|
+
|
|
12
|
+
#List out all the files to be documented.
|
|
13
|
+
rdoc.rdoc_files.include("lib/**/*.rb", "license.txt", "README.md")
|
|
14
|
+
|
|
15
|
+
#Make all access levels visible.
|
|
16
|
+
rdoc.options << '--visibility' << 'private'
|
|
17
|
+
#rdoc.options << '--verbose'
|
|
18
|
+
#rdoc.options << '--coverage-report'
|
|
19
|
+
|
|
20
|
+
#Set a title.
|
|
21
|
+
rdoc.options << '--title' << 'fOOrth Language Internals'
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#Run the fOOrth unit test suite.
|
|
26
|
+
Rake::TestTask.new do |t|
|
|
27
|
+
#List out all the test files.
|
|
28
|
+
t.test_files = FileList['tests/**/*.rb']
|
|
29
|
+
t.verbose = false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#Run the fOOrth integration test suite.
|
|
33
|
+
Rake::TestTask.new(:integration) do |t|
|
|
34
|
+
#List out all the test files.
|
|
35
|
+
t.test_files = FileList['integration/*.rb']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc "Run a scan for smelly code!"
|
|
39
|
+
task :reek do |t|
|
|
40
|
+
`reek --no-color lib > reek.txt`
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
desc "Fire up an IRB session with fOOrth preloaded."
|
|
44
|
+
task :console do
|
|
45
|
+
require 'irb'
|
|
46
|
+
require 'irb/completion'
|
|
47
|
+
require './lib/fOOrth'
|
|
48
|
+
puts "Starting an IRB console for fOOrth."
|
|
49
|
+
ARGV.clear
|
|
50
|
+
IRB.start
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
desc "Run an Interactive fOOrth Session."
|
|
54
|
+
task :run do
|
|
55
|
+
require './lib/fOOrth'
|
|
56
|
+
ARGV.clear
|
|
57
|
+
XfOOrth::main
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
desc "What version of fOOrth is this?"
|
|
61
|
+
task :vers do |t|
|
|
62
|
+
puts
|
|
63
|
+
puts "fOOrth version = #{XfOOrth::VERSION}"
|
|
64
|
+
end
|
|
65
|
+
|
data/reek.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0 total warnings
|
data/sire.rb
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# A Simple Interactive Ruby Environment
|
|
3
|
+
|
|
4
|
+
$no_alias_read_line_module = true
|
|
5
|
+
require 'mini_readline'
|
|
6
|
+
require 'pp'
|
|
7
|
+
|
|
8
|
+
if ARGV[0] == 'local'
|
|
9
|
+
require_relative 'lib/fOOrth'
|
|
10
|
+
puts "\nOption(local) Loaded fOOrth from the local code folder."
|
|
11
|
+
elsif defined?(XfOOrth)
|
|
12
|
+
puts "The fOOrth system is already loaded."
|
|
13
|
+
else
|
|
14
|
+
begin
|
|
15
|
+
require 'fOOrth'
|
|
16
|
+
puts "\nLoaded fOOrth from the system gem."
|
|
17
|
+
rescue LoadError
|
|
18
|
+
require_relative 'lib/fOOrth'
|
|
19
|
+
puts "\nLoaded fOOrth from the local code folder."
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
puts "fOOrth version = #{XfOOrth::VERSION}"
|
|
24
|
+
puts
|
|
25
|
+
|
|
26
|
+
class Object
|
|
27
|
+
#Generate the class lineage of the object.
|
|
28
|
+
def classes
|
|
29
|
+
begin
|
|
30
|
+
result = ""
|
|
31
|
+
klass = self.instance_of?(Class) ? self : self.class
|
|
32
|
+
|
|
33
|
+
begin
|
|
34
|
+
result << klass.to_s
|
|
35
|
+
klass = klass.superclass
|
|
36
|
+
result << " < " if klass
|
|
37
|
+
end while klass
|
|
38
|
+
|
|
39
|
+
result
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class SIRE
|
|
45
|
+
#Set up the interactive session.
|
|
46
|
+
def initialize
|
|
47
|
+
@_done = false
|
|
48
|
+
@_edit = MiniReadline::Readline.new(history: true,
|
|
49
|
+
auto_complete: true,
|
|
50
|
+
auto_source: MiniReadline::QuotedFileFolderSource,
|
|
51
|
+
eoi_detect: true)
|
|
52
|
+
|
|
53
|
+
puts "Welcome to a Simple Interactive Ruby Environment\n"
|
|
54
|
+
puts
|
|
55
|
+
puts "Local commands:"
|
|
56
|
+
puts " q - quit SIRE."
|
|
57
|
+
puts " r - run fOOrth."
|
|
58
|
+
puts " v - version manifest"
|
|
59
|
+
puts "obj classes - show the obj's class heritage."
|
|
60
|
+
puts
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
#Quit the interactive session.
|
|
64
|
+
def q
|
|
65
|
+
@_done = true
|
|
66
|
+
puts
|
|
67
|
+
"Bye bye for now!"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def r
|
|
71
|
+
ARGV.clear
|
|
72
|
+
XfOOrth::main.data_stack
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def v
|
|
76
|
+
puts "Version Manifest"
|
|
77
|
+
mods = ObjectSpace.each_object(Module).select{|c| c.const_defined?("VERSION")}
|
|
78
|
+
width = (mods.max_by{|m| m.to_s.length}).to_s.length
|
|
79
|
+
list = mods.map {|m| "#{m.to_s.ljust(width)} #{m.const_get(:VERSION)}" }
|
|
80
|
+
list.sort
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
#Load and run a file
|
|
84
|
+
def l(file_name)
|
|
85
|
+
@_break = false
|
|
86
|
+
lines = IO.readlines(file_name)
|
|
87
|
+
|
|
88
|
+
lines.each do |line|
|
|
89
|
+
exec_line(line)
|
|
90
|
+
return if @_break
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
"End of file '#{file_name}'."
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
#Execute a single line.
|
|
97
|
+
def exec_line(line)
|
|
98
|
+
result = eval line
|
|
99
|
+
pp result unless line.length == 0
|
|
100
|
+
|
|
101
|
+
rescue Interrupt => e
|
|
102
|
+
@_break = true
|
|
103
|
+
puts "\nExecution Interrupted!"
|
|
104
|
+
puts "\n#{e.class} detected: #{e}\n"
|
|
105
|
+
puts e.backtrace
|
|
106
|
+
puts "\n"
|
|
107
|
+
|
|
108
|
+
rescue Exception => e
|
|
109
|
+
@_break = true
|
|
110
|
+
puts "\n#{e.class} detected: #{e}\n"
|
|
111
|
+
puts e.backtrace
|
|
112
|
+
puts
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
#Run the interactive session.
|
|
116
|
+
def run_sire
|
|
117
|
+
until @_done
|
|
118
|
+
@_break = false
|
|
119
|
+
exec_line(@_edit.readline(prompt: 'SIRE>'))
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
puts "\n\n"
|
|
123
|
+
|
|
124
|
+
rescue MiniReadlineEOI, Interrupt => e
|
|
125
|
+
puts "\nInterrupted! Program Terminating."
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
if __FILE__ == $0
|
|
131
|
+
SIRE.new.run_sire
|
|
132
|
+
end
|
data/t.txt
ADDED
data/test.foorth
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
$exclude_fOOrth_library = true
|
|
4
|
+
require_relative '../../lib/fOOrth'
|
|
5
|
+
gem 'minitest'
|
|
6
|
+
require 'minitest/autorun'
|
|
7
|
+
require 'minitest_visible'
|
|
8
|
+
|
|
9
|
+
class MockClass
|
|
10
|
+
def initialize; @data = {}; end
|
|
11
|
+
def []=(index, value); @data[index] = value; end
|
|
12
|
+
def map_foorth_shared(index); @data[index]; end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class MockObject
|
|
16
|
+
def initialize; @data = {}; end
|
|
17
|
+
def []=(index, value); @data[index] = value; end
|
|
18
|
+
def map_foorth_exclusive(index); @data[index]; end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
#Test the monkey patches applied to the Object class.
|
|
22
|
+
class ContextTester < Minitest::Test
|
|
23
|
+
|
|
24
|
+
#Track mini-test progress.
|
|
25
|
+
include MinitestVisible
|
|
26
|
+
|
|
27
|
+
def test_data_store
|
|
28
|
+
context = XfOOrth::Context.new(45, stuff: 'buy', price: :plenty)
|
|
29
|
+
|
|
30
|
+
assert_equal(context.previous, 45)
|
|
31
|
+
assert_equal(context[:stuff], 'buy')
|
|
32
|
+
assert_equal(context[:price], :plenty)
|
|
33
|
+
|
|
34
|
+
context[:stuff] = 'sell'
|
|
35
|
+
assert_equal(context[:stuff], 'sell')
|
|
36
|
+
assert_equal(context[:price], :plenty)
|
|
37
|
+
|
|
38
|
+
context[:price] = 9.95
|
|
39
|
+
assert_equal(context[:stuff], 'sell')
|
|
40
|
+
assert_equal(context[:price], 9.95)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
#Test level counting
|
|
44
|
+
def test_level_tracking
|
|
45
|
+
context = XfOOrth::Context.new(nil, stuff: 'buy')
|
|
46
|
+
assert_equal(context.depth, 1)
|
|
47
|
+
|
|
48
|
+
context = XfOOrth::Context.new(context, stuff: 'other')
|
|
49
|
+
assert_equal(context.depth, 2)
|
|
50
|
+
|
|
51
|
+
context = XfOOrth::Context.new(context, stuff: 'more')
|
|
52
|
+
assert_equal(context.depth, 3)
|
|
53
|
+
|
|
54
|
+
context = context.previous
|
|
55
|
+
assert_equal(context.depth, 2)
|
|
56
|
+
|
|
57
|
+
context = context.previous
|
|
58
|
+
assert_equal(context.depth, 1)
|
|
59
|
+
|
|
60
|
+
context = context.previous
|
|
61
|
+
assert_equal(context, nil)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_the_nesting_of_scopes
|
|
65
|
+
context = XfOOrth::Context.new(nil, stuff: 'buy')
|
|
66
|
+
assert_equal(context[:foo], nil)
|
|
67
|
+
assert_equal(context[:jelly], nil)
|
|
68
|
+
assert_equal(context[:stuff], 'buy')
|
|
69
|
+
context[:foo] = 1
|
|
70
|
+
context[:jelly] = 'donut'
|
|
71
|
+
assert_equal(context[:jelly], 'donut')
|
|
72
|
+
assert_equal(context[:stuff], 'buy')
|
|
73
|
+
assert_equal(context[:foo], 1)
|
|
74
|
+
|
|
75
|
+
context = XfOOrth::Context.new(context, stuff: 'other')
|
|
76
|
+
assert_equal(context[:foo], 1)
|
|
77
|
+
assert_equal(context[:jelly], 'donut')
|
|
78
|
+
assert_equal(context[:stuff], 'other')
|
|
79
|
+
context[:foo] = 2
|
|
80
|
+
assert_equal(context[:jelly], 'donut')
|
|
81
|
+
assert_equal(context[:stuff], 'other')
|
|
82
|
+
assert_equal(context[:foo], 2)
|
|
83
|
+
|
|
84
|
+
context = XfOOrth::Context.new(context, stuff: 'more')
|
|
85
|
+
assert_equal(context[:foo], 2)
|
|
86
|
+
assert_equal(context[:jelly], 'donut')
|
|
87
|
+
assert_equal(context[:stuff], 'more')
|
|
88
|
+
context[:foo] = 3
|
|
89
|
+
context[:jelly] = 'Berliner'
|
|
90
|
+
assert_equal(context[:jelly], 'Berliner')
|
|
91
|
+
assert_equal(context[:stuff], 'more')
|
|
92
|
+
assert_equal(context[:foo], 3)
|
|
93
|
+
|
|
94
|
+
context = context.previous
|
|
95
|
+
assert_equal(context[:foo], 2)
|
|
96
|
+
assert_equal(context[:jelly], 'donut')
|
|
97
|
+
assert_equal(context[:stuff], 'other')
|
|
98
|
+
|
|
99
|
+
context = context.previous
|
|
100
|
+
assert_equal(context[:foo], 1)
|
|
101
|
+
assert_equal(context[:jelly], 'donut')
|
|
102
|
+
assert_equal(context[:stuff], 'buy')
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_the_local_mapping_of_symbols
|
|
106
|
+
context = XfOOrth::Context.new(nil)
|
|
107
|
+
|
|
108
|
+
name = 'b'
|
|
109
|
+
sym = XfOOrth::SymbolMap.add_entry(name)
|
|
110
|
+
context[sym] = XfOOrth::VmSpec.new(name, sym)
|
|
111
|
+
spec = context.map(name)
|
|
112
|
+
assert(spec.is_a?(XfOOrth::VmSpec))
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def test_the_class_mapping_of_symbols
|
|
116
|
+
mk = MockClass.new
|
|
117
|
+
context = XfOOrth::Context.new(nil, cls: mk)
|
|
118
|
+
|
|
119
|
+
name = '.c'
|
|
120
|
+
sym = XfOOrth::SymbolMap.add_entry(name)
|
|
121
|
+
mk[sym] = XfOOrth::TosSpec.new(name, sym)
|
|
122
|
+
spec = context.map(name)
|
|
123
|
+
assert(spec.is_a?(XfOOrth::TosSpec))
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_the_exclusive_mapping_of_symbols
|
|
127
|
+
mk = MockObject.new
|
|
128
|
+
context = XfOOrth::Context.new(nil, obj: mk)
|
|
129
|
+
|
|
130
|
+
name = '.d'
|
|
131
|
+
sym = XfOOrth::SymbolMap.add_entry(name)
|
|
132
|
+
mk[sym] = XfOOrth::TosSpec.new(name, sym)
|
|
133
|
+
spec = context.map(name)
|
|
134
|
+
assert(spec.is_a?(XfOOrth::TosSpec))
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def test_that_it_verifies_sets
|
|
138
|
+
context = XfOOrth::Context.new(nil, mode: :Execute, ctrl: :colon)
|
|
139
|
+
|
|
140
|
+
assert(context.check_set(:mode, [:Execute, :Compile]))
|
|
141
|
+
|
|
142
|
+
assert_raises(XfOOrth::XfOOrthError) do
|
|
143
|
+
context.check_set(:mode, [:Compile, :Deferred])
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
assert(context.check_set(:stuff, [nil]))
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def test_the_locating_of_the_receiver
|
|
150
|
+
context = XfOOrth::Context.new(nil, vm: 'vm_sample')
|
|
151
|
+
assert_equal('vm_sample', context.recvr)
|
|
152
|
+
|
|
153
|
+
context = XfOOrth::Context.new(context, cls: 'cls_sample')
|
|
154
|
+
assert_equal('cls_sample', context.recvr)
|
|
155
|
+
|
|
156
|
+
context = XfOOrth::Context.new(context, obj: 'obj_sample')
|
|
157
|
+
assert_equal('obj_sample', context.recvr)
|
|
158
|
+
|
|
159
|
+
context = XfOOrth::Context.new(nil)
|
|
160
|
+
|
|
161
|
+
assert_raises(XfOOrth::XfOOrthError) do
|
|
162
|
+
context.recvr
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def test_adding_and_removing_local_methods
|
|
167
|
+
context = XfOOrth::Context.new(nil, vm: 'vm_sample')
|
|
168
|
+
name = 'lm'
|
|
169
|
+
sym = XfOOrth::SymbolMap.add_entry(name)
|
|
170
|
+
spec = context.create_local_method(name, XfOOrth::LocalSpec, [])
|
|
171
|
+
|
|
172
|
+
assert_equal(spec, context[sym])
|
|
173
|
+
|
|
174
|
+
context.remove_local_method(name)
|
|
175
|
+
|
|
176
|
+
assert_equal(nil, context[sym])
|
|
177
|
+
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|