fOOrth 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|