fOOrth 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +9 -5
- data/integration/array_lib_tests.rb +2 -0
- data/integration/clone_lib_tests.rb +21 -11
- data/integration/standard_lib_tests.rb +5 -2
- data/integration/string_lib_tests.rb +304 -14
- data/integration/thread_lib_tests.rb +2 -2
- data/lib/fOOrth/compiler/process/string.rb +8 -1
- data/lib/fOOrth/compiler/source.rb +13 -2
- data/lib/fOOrth/compiler/source/console.rb +19 -3
- data/lib/fOOrth/core/class.rb +2 -2
- data/lib/fOOrth/library/array_library.rb +5 -1
- data/lib/fOOrth/library/class_library.rb +1 -1
- data/lib/fOOrth/library/command_library.rb +2 -2
- data/lib/fOOrth/library/duration_library.rb +1 -1
- data/lib/fOOrth/library/hash_library.rb +1 -1
- data/lib/fOOrth/library/in_stream_library.rb +3 -3
- data/lib/fOOrth/library/object_library.rb +11 -1
- data/lib/fOOrth/library/out_stream_library.rb +6 -6
- data/lib/fOOrth/library/procedure_library.rb +1 -1
- data/lib/fOOrth/library/stdio_library.rb +1 -1
- data/lib/fOOrth/library/string_library.rb +82 -33
- data/lib/fOOrth/library/thread_library.rb +1 -1
- data/lib/fOOrth/library/vm_library.rb +1 -1
- data/lib/fOOrth/monkey_patch/numeric.rb +1 -1
- data/lib/fOOrth/monkey_patch/object.rb +5 -0
- data/lib/fOOrth/monkey_patch/string.rb +58 -1
- data/lib/fOOrth/version.rb +1 -1
- data/tests/monkey_patch/string_test.rb +10 -2
- metadata +2 -2
@@ -71,11 +71,11 @@ class ThreadLibraryTester < Minitest::Test
|
|
71
71
|
foorth_run('$tmtx .lock $tmtx .unlock ')
|
72
72
|
foorth_equal('$tmtx .do{{ 3 4 + }}', [7])
|
73
73
|
|
74
|
-
foorth_run('"" val$: $tmtx_str')
|
74
|
+
foorth_run('""* val$: $tmtx_str')
|
75
75
|
foorth_equal('{{ $tmtx .do{{ 0 10 do $tmtx_str "@" << loop }} }} ' +
|
76
76
|
'.start drop $tmtx .do{{ $tmtx_str }} ', ["@"*10])
|
77
77
|
|
78
|
-
foorth_run('"" val$: $tmtx_str')
|
78
|
+
foorth_run('""* val$: $tmtx_str')
|
79
79
|
foorth_equal('{{ Mutex .do{{ 0 10 do $tmtx_str "@" << loop }} }} ' +
|
80
80
|
'.start drop Mutex .do{{ $tmtx_str }} ', ["@"*10])
|
81
81
|
end
|
@@ -12,7 +12,14 @@ module XfOOrth
|
|
12
12
|
#* word - The text of the word.
|
13
13
|
def string_parms(token, word)
|
14
14
|
if word.end_with?('"')
|
15
|
-
|
15
|
+
string_value = parser.get_string.foorth_embed
|
16
|
+
|
17
|
+
if parser.source.peek == '*'
|
18
|
+
parser.source.get
|
19
|
+
token.add("vm.push(StringBuffer.new(#{string_value})); ")
|
20
|
+
else
|
21
|
+
token.add("vm.push(#{string_value}.freeze); ")
|
22
|
+
end
|
16
23
|
end
|
17
24
|
end
|
18
25
|
|
@@ -13,21 +13,23 @@ module XfOOrth
|
|
13
13
|
def initialize
|
14
14
|
reset_read_point
|
15
15
|
@eof = false
|
16
|
+
@peek_buffer = nil
|
16
17
|
end
|
17
18
|
|
18
19
|
#Close the source.
|
19
20
|
def close
|
20
21
|
@eoln = true
|
21
22
|
@eof = true
|
23
|
+
@peek_buffer = nil
|
22
24
|
end
|
23
25
|
|
24
26
|
#Get the next character of input data
|
25
27
|
#<br>Returns:
|
26
28
|
#* The next character or nil if none are available.
|
27
29
|
def get
|
28
|
-
return nil if @eof
|
30
|
+
return nil if (@eof && !@peek_buffer)
|
29
31
|
|
30
|
-
read do
|
32
|
+
@peek_buffer || read do
|
31
33
|
begin
|
32
34
|
@read_step.next.rstrip
|
33
35
|
rescue StopIteration
|
@@ -35,6 +37,15 @@ module XfOOrth
|
|
35
37
|
nil
|
36
38
|
end
|
37
39
|
end
|
40
|
+
ensure
|
41
|
+
@peek_buffer = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
#Peek ahead by one character.
|
45
|
+
#<br>Returns:
|
46
|
+
#* A peek at next character or nil if none are available.
|
47
|
+
def peek
|
48
|
+
@peek_buffer ||= get
|
38
49
|
end
|
39
50
|
|
40
51
|
#Has the source reached the end of the available data?
|
@@ -11,6 +11,8 @@ module XfOOrth
|
|
11
11
|
|
12
12
|
#Initialize a new console command source.
|
13
13
|
def initialize
|
14
|
+
@peek_buffer = nil
|
15
|
+
|
14
16
|
reset_read_point
|
15
17
|
|
16
18
|
auto_src = lambda { SymbolMap.forward_map.keys.sort }
|
@@ -22,16 +24,30 @@ module XfOOrth
|
|
22
24
|
eoi_detect: true)
|
23
25
|
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
+
#Close the console source.
|
28
|
+
def close
|
29
|
+
@peek_buffer = nil
|
30
|
+
reset_read_point
|
31
|
+
end
|
32
|
+
|
33
|
+
alias flush close
|
27
34
|
|
28
35
|
#Get the next character of command text from the user.
|
29
36
|
#<br>Returns
|
30
37
|
#* The next character of user input as a string.
|
31
38
|
def get
|
32
|
-
read do
|
39
|
+
@peek_buffer || read do
|
33
40
|
@edit.readline(prompt: prompt).rstrip
|
34
41
|
end
|
42
|
+
ensure
|
43
|
+
@peek_buffer = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
#Peek ahead by one character.
|
47
|
+
#<br>Returns:
|
48
|
+
#* A peek at next character or nil if none are available.
|
49
|
+
def peek
|
50
|
+
@peek_buffer ||= get
|
35
51
|
end
|
36
52
|
|
37
53
|
#Has the scanning of the text reached the end of input?
|
data/lib/fOOrth/core/class.rb
CHANGED
@@ -7,14 +7,14 @@ class Class
|
|
7
7
|
#<br>Decree!
|
8
8
|
#* These are to be the only references to @_private_foorth_name!
|
9
9
|
def foorth_name
|
10
|
-
@_private_foorth_name ||= name
|
10
|
+
@_private_foorth_name ||= name.freeze
|
11
11
|
end
|
12
12
|
|
13
13
|
#Set the foorth name of this class.
|
14
14
|
#<br>Decree!
|
15
15
|
#* These are to be the only references to @_private_foorth_name!
|
16
16
|
def foorth_name=(new_name)
|
17
|
-
@_private_foorth_name = new_name
|
17
|
+
@_private_foorth_name = new_name.freeze
|
18
18
|
end
|
19
19
|
|
20
20
|
#Access/create the class's shared fOOrth dictionary.
|
@@ -119,6 +119,10 @@ module XfOOrth
|
|
119
119
|
Array.create_shared_method('<<', NosSpec, [],
|
120
120
|
&lambda {|vm| vm.poke(self << vm.peek); })
|
121
121
|
|
122
|
+
# [ [ 3 1 2 ] n ] >> [ [ n 3 1 2 ] ]
|
123
|
+
Array.create_shared_method('>>', NosSpec, [],
|
124
|
+
&lambda {|vm| vm.poke(self.insert(0, vm.peek)); })
|
125
|
+
|
122
126
|
# [[3 1 2] n] + [[3 1 2 n]]
|
123
127
|
Array.create_shared_method('+', NosSpec, [],
|
124
128
|
&lambda {|vm| vm.poke(self + vm.peek.in_array); })
|
@@ -474,7 +478,7 @@ module XfOOrth
|
|
474
478
|
end
|
475
479
|
end
|
476
480
|
|
477
|
-
vm.push(result + "]")
|
481
|
+
vm.push((result + "]").freeze)
|
478
482
|
})
|
479
483
|
|
480
484
|
# [ l 2 3 ... n ] .strmax [ widest ]
|
@@ -11,7 +11,7 @@ module XfOOrth
|
|
11
11
|
#Get the class as a string.
|
12
12
|
# [cls] .to_s ["cls as a string"]
|
13
13
|
Class.create_shared_method('.to_s', TosSpec, [], &lambda {|vm|
|
14
|
-
vm.push(self.foorth_name || "AnonymousClass<#{self.object_id}>")
|
14
|
+
vm.push(self.foorth_name || "AnonymousClass<#{self.object_id}>".freeze)
|
15
15
|
})
|
16
16
|
|
17
17
|
#The .parent_class method. Retrieves the parent class of a class.
|
@@ -117,7 +117,7 @@ module XfOOrth
|
|
117
117
|
error "F50: Unable to locate file #{file_name}"
|
118
118
|
end
|
119
119
|
|
120
|
-
vm.process_file(file_name)
|
120
|
+
vm.process_file(file_name.freeze)
|
121
121
|
|
122
122
|
puts "Completed in #{Time.now - start_time} seconds"
|
123
123
|
})
|
@@ -180,7 +180,7 @@ module XfOOrth
|
|
180
180
|
#List the globals defined in fOOrth.
|
181
181
|
VirtualMachine.create_shared_method(')globals', VmSpec, [], &lambda {|vm|
|
182
182
|
$FOORTH_GLOBALS.keys.
|
183
|
-
select
|
183
|
+
select {|key| !($FOORTH_GLOBALS[key].has_tag?(:class))}.
|
184
184
|
collect {|key| "#{XfOOrth::SymbolMap.unmap(key)} (#{key.to_s})"}.
|
185
185
|
foorth_pretty(vm)
|
186
186
|
})
|
@@ -47,6 +47,6 @@ module XfOOrth
|
|
47
47
|
|
48
48
|
#Default conversion to string. See duration/formatter for formatted output.
|
49
49
|
Duration.create_shared_method('.to_s', TosSpec, [], &lambda {|vm|
|
50
|
-
vm.push("Duration instance <#{self.period.to_f} seconds>" )
|
50
|
+
vm.push("Duration instance <#{self.period.to_f} seconds>".freeze )
|
51
51
|
})
|
52
52
|
end
|
@@ -25,13 +25,13 @@ module XfOOrth
|
|
25
25
|
|
26
26
|
# ["file_name", InStream] .open [an_instream]
|
27
27
|
in_stream.create_exclusive_method('.open', TosSpec, [], &lambda {|vm|
|
28
|
-
file_name = vm.pop.to_s
|
28
|
+
file_name = vm.pop.to_s.freeze
|
29
29
|
vm.push(XfOOrth_InStream.new(file_name))
|
30
30
|
})
|
31
31
|
|
32
32
|
in_stream.create_exclusive_method('.open{{', NosSpec, [], &lambda {|vm|
|
33
33
|
block = vm.pop
|
34
|
-
file_name = vm.pop.to_s
|
34
|
+
file_name = vm.pop.to_s.freeze
|
35
35
|
in_stream = XfOOrth_InStream.new(file_name)
|
36
36
|
|
37
37
|
begin
|
@@ -71,7 +71,7 @@ module XfOOrth
|
|
71
71
|
# [file_name InStream] .get_all [["line 1", "line 2", ... "line n"]]
|
72
72
|
in_stream.create_exclusive_method('.get_all', TosSpec, [], &lambda {|vm|
|
73
73
|
begin
|
74
|
-
file_name = vm.pop.to_s
|
74
|
+
file_name = vm.pop.to_s.freeze
|
75
75
|
vm.push(IO.readlines(file_name).map{|line| line.chomp })
|
76
76
|
rescue
|
77
77
|
error "F50: Unable to open the file #{file_name} for reading all."
|
@@ -28,7 +28,17 @@ module XfOOrth
|
|
28
28
|
#Get the object as a string.
|
29
29
|
# [obj] .to_s ["obj as a string"]
|
30
30
|
Object.create_shared_method('.to_s', TosSpec, [],
|
31
|
-
&lambda {|vm| vm.push(self.to_s)})
|
31
|
+
&lambda {|vm| vm.push(self.to_s.freeze)})
|
32
|
+
|
33
|
+
#Get the object as a string.
|
34
|
+
# [obj] .to_s ["obj as a string"]
|
35
|
+
Object.create_shared_method('.to_s*', TosSpec, [],
|
36
|
+
&lambda {|vm| vm.push(StringBuffer.new(self.to_s.dup))})
|
37
|
+
|
38
|
+
#Get the object as a string.
|
39
|
+
# [obj] .to_s ["obj as a string"]
|
40
|
+
String.create_shared_method('.to_s*', TosSpec, [],
|
41
|
+
&lambda {|vm| vm.push(StringBuffer.new(self.dup))})
|
32
42
|
|
33
43
|
#Get the length of the object as a string.
|
34
44
|
# [obj] .strlen [n]; the length of the object's to_s string
|
@@ -28,14 +28,14 @@ module XfOOrth
|
|
28
28
|
|
29
29
|
# ["file_name" OutStream] .create [an_outstream]
|
30
30
|
out_stream.create_exclusive_method('.create', TosSpec, [], &lambda {|vm|
|
31
|
-
file_name = vm.pop.to_s
|
31
|
+
file_name = vm.pop.to_s.freeze
|
32
32
|
vm.push(XfOOrth_OutStream.new(file_name, 'w'))
|
33
33
|
})
|
34
34
|
|
35
35
|
# ["file_name" OutStream] .create{{ ... }} []
|
36
36
|
out_stream.create_exclusive_method('.create{{', TosSpec, [], &lambda {|vm|
|
37
37
|
block = vm.pop
|
38
|
-
file_name = vm.pop.to_s
|
38
|
+
file_name = vm.pop.to_s.freeze
|
39
39
|
out_stream = XfOOrth_OutStream.new(file_name, 'w')
|
40
40
|
|
41
41
|
begin
|
@@ -48,7 +48,7 @@ module XfOOrth
|
|
48
48
|
# ["file_name" OutStream] .append{{ ... }} []
|
49
49
|
out_stream.create_exclusive_method('.append{{', TosSpec, [], &lambda {|vm|
|
50
50
|
block = vm.pop
|
51
|
-
file_name = vm.pop.to_s
|
51
|
+
file_name = vm.pop.to_s.freeze
|
52
52
|
out_stream = XfOOrth_OutStream.new(file_name, 'a')
|
53
53
|
|
54
54
|
begin
|
@@ -60,7 +60,7 @@ module XfOOrth
|
|
60
60
|
|
61
61
|
# ["file_name" OutStream] .append [an_outstream]
|
62
62
|
out_stream.create_exclusive_method('.append', TosSpec, [], &lambda {|vm|
|
63
|
-
file_name = vm.pop.to_s
|
63
|
+
file_name = vm.pop.to_s.freeze
|
64
64
|
vm.push(XfOOrth_OutStream.new(file_name, 'a'))
|
65
65
|
})
|
66
66
|
|
@@ -119,7 +119,7 @@ module XfOOrth
|
|
119
119
|
|
120
120
|
# [text_array "file_name" OutStream] .put_all []; Write the array to file_name
|
121
121
|
out_stream.create_exclusive_method('.put_all', TosSpec, [], &lambda {|vm|
|
122
|
-
file_name = vm.pop.to_s
|
122
|
+
file_name = vm.pop.to_s.freeze
|
123
123
|
file_source = vm.pop
|
124
124
|
out_stream = XfOOrth_OutStream.new(file_name, 'w')
|
125
125
|
|
@@ -132,7 +132,7 @@ module XfOOrth
|
|
132
132
|
|
133
133
|
# [text_array "file_name" OutStream] .append_all []; Append the array to file_name
|
134
134
|
out_stream.create_exclusive_method('.append_all', TosSpec, [], &lambda {|vm|
|
135
|
-
file_name = vm.pop.to_s
|
135
|
+
file_name = vm.pop.to_s.freeze
|
136
136
|
file_source = vm.pop
|
137
137
|
out_stream = XfOOrth_OutStream.new(file_name, 'a')
|
138
138
|
|
@@ -47,7 +47,7 @@ module XfOOrth
|
|
47
47
|
#Get a string from the console.
|
48
48
|
# [] accept"prompt" [string]; gets a string from the console.
|
49
49
|
VirtualMachine.create_shared_method('accept"', VmSpec, [],
|
50
|
-
&lambda {|vm| poke(MiniReadline.readline(peek.to_s, true)); })
|
50
|
+
&lambda {|vm| poke(MiniReadline.readline(peek.to_s, true).freeze); })
|
51
51
|
|
52
52
|
#Get a string from the console.
|
53
53
|
# "prompt" [] .accept [string]; gets a string from the console.
|
@@ -6,13 +6,21 @@ module XfOOrth
|
|
6
6
|
#Connect the String class to the fOOrth class system.
|
7
7
|
String.create_foorth_proxy
|
8
8
|
|
9
|
+
#Connect the StringBuffer class to the fOOrth class system.
|
10
|
+
StringBuffer.create_foorth_proxy
|
11
|
+
|
9
12
|
# A no operation place holder for string literals
|
10
13
|
VirtualMachine.create_shared_method('"', MacroSpec, [:macro, " "])
|
11
14
|
|
15
|
+
#Is this mutable? StringBuffers are, Strings are not.
|
16
|
+
# [a] .mutable? [flag]
|
17
|
+
String.create_shared_method('.mutable?', TosSpec, [],
|
18
|
+
&lambda {|vm| vm.push(!self.frozen?); })
|
19
|
+
|
12
20
|
# [string] .each{{ ... }} [unspecified]
|
13
21
|
String.create_shared_method('.each{{', NosSpec, [], &lambda { |vm|
|
14
22
|
block, idx = vm.pop, 0
|
15
|
-
self.chars { |val| block.call(vm, val, idx); idx += 1 }
|
23
|
+
self.chars { |val| block.call(vm, val.freeze, idx); idx += 1 }
|
16
24
|
})
|
17
25
|
|
18
26
|
#Some comparison operators
|
@@ -39,32 +47,48 @@ module XfOOrth
|
|
39
47
|
|
40
48
|
#Some string manipulation methods.
|
41
49
|
# [n a] .ljust ['a ']; left justify
|
42
|
-
String.create_shared_method('.ljust', TosSpec, [],
|
43
|
-
|
50
|
+
String.create_shared_method('.ljust', TosSpec, [], &lambda {|vm|
|
51
|
+
vm.poke(self.to_s.ljust(Integer.foorth_coerce(vm.peek)).freeze);
|
52
|
+
})
|
44
53
|
|
45
54
|
# [n a] .cjust [' a ']; center justify
|
46
|
-
String.create_shared_method('.cjust', TosSpec, [],
|
47
|
-
|
55
|
+
String.create_shared_method('.cjust', TosSpec, [], &lambda {|vm|
|
56
|
+
vm.poke(self.to_s.center(Integer.foorth_coerce(vm.peek)).freeze);
|
57
|
+
})
|
48
58
|
|
49
59
|
# [n a] .rjust [' a']; right justify
|
50
|
-
String.create_shared_method('.rjust', TosSpec, [],
|
51
|
-
|
60
|
+
String.create_shared_method('.rjust', TosSpec, [], &lambda {|vm|
|
61
|
+
vm.poke(self.to_s.rjust(Integer.foorth_coerce(vm.peek)).freeze);
|
62
|
+
})
|
52
63
|
|
53
64
|
# [" a "] .lstrip ["a "]; left strip
|
54
65
|
String.create_shared_method('.lstrip', TosSpec, [],
|
55
|
-
&lambda {|vm| vm.push(self.lstrip); })
|
66
|
+
&lambda {|vm| vm.push(self.to_s.lstrip.freeze); })
|
67
|
+
|
68
|
+
# [" a "*] .lstrip* []; left strip in place.
|
69
|
+
StringBuffer.create_shared_method('.lstrip*', TosSpec, [],
|
70
|
+
&lambda {|vm| self.lstrip! })
|
56
71
|
|
57
72
|
# [" a "] .strip ["a"]; left and right strip
|
58
73
|
String.create_shared_method('.strip', TosSpec, [],
|
59
|
-
&lambda {|vm| vm.push(self.strip); })
|
74
|
+
&lambda {|vm| vm.push(self.to_s.strip.freeze); })
|
75
|
+
|
76
|
+
# [" a "*] .strip* []; left and right strip in place
|
77
|
+
StringBuffer.create_shared_method('.strip*', TosSpec, [],
|
78
|
+
&lambda {|vm| self.strip! })
|
60
79
|
|
61
80
|
# [" a "] .rstrip [" a"]; right strip
|
62
81
|
String.create_shared_method('.rstrip', TosSpec, [],
|
63
|
-
&lambda {|vm| vm.push(self.rstrip); })
|
82
|
+
&lambda {|vm| vm.push(self.to_s.rstrip.freeze); })
|
83
|
+
|
84
|
+
# [" a "*] .rstrip* []; right strip in place
|
85
|
+
StringBuffer.create_shared_method('.rstrip*', TosSpec, [],
|
86
|
+
&lambda {|vm| self.rstrip! })
|
64
87
|
|
88
|
+
#The shared block for string formatting.
|
65
89
|
format_action = lambda do |vm|
|
66
90
|
begin
|
67
|
-
vm.poke(vm.peek % self.in_array)
|
91
|
+
vm.poke((vm.peek % self.in_array).freeze)
|
68
92
|
rescue => err
|
69
93
|
vm.data_stack.pop
|
70
94
|
error "F40: Formating error: #{err.message}."
|
@@ -77,7 +101,14 @@ module XfOOrth
|
|
77
101
|
# [object_or_array] f"fmt_str" ['a formatted string']
|
78
102
|
Object.create_shared_method('f"', NosSpec, [], &format_action)
|
79
103
|
|
80
|
-
parse_action = lambda
|
104
|
+
parse_action = lambda do |vm|
|
105
|
+
begin
|
106
|
+
vm.poke(self.sscanf(vm.peek).map{|obj| obj.foorth_string_freeze} )
|
107
|
+
rescue => err
|
108
|
+
vm.data_stack.pop
|
109
|
+
error "F40: Parsing error: #{err.message}."
|
110
|
+
end
|
111
|
+
end
|
81
112
|
|
82
113
|
# [a_str fmt_str] parse [result_array]
|
83
114
|
String.create_shared_method('parse', NosSpec, [], &parse_action)
|
@@ -90,16 +121,16 @@ module XfOOrth
|
|
90
121
|
|
91
122
|
# [w 'abcdefgh'] .left ['ab'] // Assumes w = 2
|
92
123
|
String.create_shared_method('.left', TosSpec, [],
|
93
|
-
&lambda {|vm| vm.poke(self[0...(Integer.foorth_coerce(vm.peek))]); })
|
124
|
+
&lambda {|vm| vm.poke(self.to_s[0...(Integer.foorth_coerce(vm.peek))].freeze); })
|
94
125
|
|
95
126
|
# [w 'abcdefgh'] .-left ['cdefgh'] // Assumes w = 2
|
96
127
|
String.create_shared_method('.-left', TosSpec, [],
|
97
|
-
&lambda {|vm| vm.poke(self[(Integer.foorth_coerce(vm.peek))..-1]); })
|
128
|
+
&lambda {|vm| vm.poke(self.to_s[(Integer.foorth_coerce(vm.peek))..-1].freeze); })
|
98
129
|
|
99
130
|
# [w '123''abcdefgh'] .+left ['123cdefgh'] // Assumes w = 2
|
100
131
|
String.create_shared_method('.+left', TosSpec, [], &lambda {|vm|
|
101
132
|
ins = vm.pop.to_s
|
102
|
-
vm.poke(ins + self[(Integer.foorth_coerce(vm.peek))..-1])
|
133
|
+
vm.poke((ins + self[(Integer.foorth_coerce(vm.peek))..-1]).freeze)
|
103
134
|
})
|
104
135
|
|
105
136
|
# ['abc' 'abcdefgh'] .left? [boolean]
|
@@ -113,14 +144,14 @@ module XfOOrth
|
|
113
144
|
String.create_shared_method('.mid', TosSpec, [], &lambda {|vm|
|
114
145
|
width = Integer.foorth_coerce(vm.pop)
|
115
146
|
posn = Integer.foorth_coerce(vm.pop)
|
116
|
-
vm.push(self[posn...(posn+width)])
|
147
|
+
vm.push(self.to_s[posn...(posn+width)].freeze)
|
117
148
|
})
|
118
149
|
|
119
150
|
# [n w 'abcdefgh'] .-mid ['abgh'] // Assumes n = 2, w = 4
|
120
151
|
String.create_shared_method('.-mid', TosSpec, [], &lambda {|vm|
|
121
152
|
width = Integer.foorth_coerce(vm.pop)
|
122
153
|
posn = Integer.foorth_coerce(vm.pop)
|
123
|
-
vm.push(self[0...posn] + self[(posn+width)..-1])
|
154
|
+
vm.push((self[0...posn] + self[(posn+width)..-1]).freeze)
|
124
155
|
})
|
125
156
|
|
126
157
|
# [n w "123" "abcdefgh"] .+mid ["ab123gh"] // Assumes n = 2, w = 4
|
@@ -128,7 +159,7 @@ module XfOOrth
|
|
128
159
|
ins = vm.pop.to_s
|
129
160
|
width = Integer.foorth_coerce(vm.pop)
|
130
161
|
posn = Integer.foorth_coerce(vm.pop)
|
131
|
-
vm.push(self[0...posn] + ins + self[(posn+width)..-1])
|
162
|
+
vm.push((self[0...posn] + ins + self[(posn+width)..-1]).freeze)
|
132
163
|
})
|
133
164
|
|
134
165
|
# [n 'cde' 'abcdefgh'] .mid? [true] // Assumes n = 2
|
@@ -146,14 +177,14 @@ module XfOOrth
|
|
146
177
|
String.create_shared_method('.midlr', TosSpec, [], &lambda {|vm|
|
147
178
|
right = Integer.foorth_coerce(vm.pop)
|
148
179
|
left = Integer.foorth_coerce(vm.pop)
|
149
|
-
vm.push(self[left...(0-right)])
|
180
|
+
vm.push(self.to_s[left...(0-right)].freeze)
|
150
181
|
})
|
151
182
|
|
152
183
|
# [l r 'abcdefgh'] .-midlr ['ah'] // Assumes l = 1, r = 1
|
153
184
|
String.create_shared_method('.-midlr', TosSpec, [], &lambda {|vm|
|
154
185
|
right = Integer.foorth_coerce(vm.pop)
|
155
186
|
left = Integer.foorth_coerce(vm.pop)
|
156
|
-
vm.push(self[0...left] + self[((0-right))..-1])
|
187
|
+
vm.push((self[0...left] + self[((0-right))..-1]).freeze)
|
157
188
|
})
|
158
189
|
|
159
190
|
# [l r "123" 'abcdefgh'] .+midlr ['a123h'] // Assumes l = 1, r = 1
|
@@ -161,24 +192,26 @@ module XfOOrth
|
|
161
192
|
ins = vm.pop.to_s
|
162
193
|
right = Integer.foorth_coerce(vm.pop)
|
163
194
|
left = Integer.foorth_coerce(vm.pop)
|
164
|
-
vm.push(self[0...left] + ins + self[((0-right))..-1])
|
195
|
+
vm.push((self[0...left] + ins + self[((0-right))..-1]).freeze)
|
165
196
|
})
|
166
197
|
|
167
198
|
#RIGHT Group
|
168
199
|
|
169
200
|
# [w 'abcdefgh'] .right ['gh'] // Assumes w = 2
|
170
|
-
String.create_shared_method('.right', TosSpec, [],
|
171
|
-
|
201
|
+
String.create_shared_method('.right', TosSpec, [], &lambda {|vm|
|
202
|
+
vm.poke(self.to_s[(0-(Integer.foorth_coerce(vm.peek)))..-1].freeze);
|
203
|
+
})
|
172
204
|
|
173
205
|
# [w 'abcdefgh'] .-right ['abcdef'] // Assumes w = 2
|
174
|
-
String.create_shared_method('.-right', TosSpec, [],
|
175
|
-
|
206
|
+
String.create_shared_method('.-right', TosSpec, [], &lambda {|vm|
|
207
|
+
vm.poke(self.to_s[0...(0-(Integer.foorth_coerce(vm.peek)))].freeze);
|
208
|
+
})
|
176
209
|
|
177
210
|
# [w "123" 'abcdefgh'] .+right ['abcdef123'] // Assumes w = 2
|
178
211
|
String.create_shared_method('.+right', TosSpec, [], &lambda {|vm|
|
179
212
|
ins = vm.pop.to_s
|
180
213
|
width = Integer.foorth_coerce(vm.pop)
|
181
|
-
vm.push(self[0...(0-width)] + ins)
|
214
|
+
vm.push((self[0...(0-width)] + ins).freeze)
|
182
215
|
})
|
183
216
|
|
184
217
|
# ['fgh' 'abcdefgh'] .right? [boolean]
|
@@ -201,16 +234,20 @@ module XfOOrth
|
|
201
234
|
|
202
235
|
# ["b", a] + ["ba"]; "ba" is a new object, distinct from "b"
|
203
236
|
String.create_shared_method('+', NosSpec, [],
|
204
|
-
&lambda {|vm| vm.poke(self + vm.peek.to_s)
|
237
|
+
&lambda {|vm| vm.poke((self + vm.peek.to_s).freeze) })
|
205
238
|
|
206
|
-
# ["b"
|
207
|
-
|
239
|
+
# ["b"*, a] << ["ba"*]; "ba"* is the same object as "b"*
|
240
|
+
StringBuffer.create_shared_method('<<', NosSpec, [],
|
208
241
|
&lambda {|vm| vm.poke(self << vm.peek.to_s); })
|
209
242
|
|
243
|
+
# ["b"*, a] >> ["ab"*]; "ab"* is the same object as "b"*
|
244
|
+
StringBuffer.create_shared_method('>>', NosSpec, [],
|
245
|
+
&lambda {|vm| vm.poke(self.prepend(vm.peek.to_s)); })
|
246
|
+
|
210
247
|
# ["b", n] * ["bbb..."]
|
211
248
|
String.create_shared_method('*', NosSpec, [], &lambda {|vm|
|
212
249
|
begin
|
213
|
-
vm.poke(self * Integer.foorth_coerce(vm.peek))
|
250
|
+
vm.poke((self.to_s * Integer.foorth_coerce(vm.peek)).freeze)
|
214
251
|
rescue
|
215
252
|
vm.data_stack.pop
|
216
253
|
raise
|
@@ -219,15 +256,27 @@ module XfOOrth
|
|
219
256
|
|
220
257
|
# ["abCD"] .to_upper ["ABCD"]
|
221
258
|
String.create_shared_method('.to_upper', TosSpec, [],
|
222
|
-
&lambda {|vm| vm.push(self.upcase)
|
259
|
+
&lambda {|vm| vm.push(self.to_s.upcase.freeze) })
|
260
|
+
|
261
|
+
# ["abCD"*] .to_upper* [] #Convert to upper case in place.
|
262
|
+
StringBuffer.create_shared_method('.to_upper*', TosSpec, [],
|
263
|
+
&lambda {|vm| self.upcase! })
|
223
264
|
|
224
265
|
# ["abCD"] .to_lower ["abcd"]
|
225
266
|
String.create_shared_method('.to_lower', TosSpec, [],
|
226
|
-
&lambda {|vm| vm.push(self.downcase)
|
267
|
+
&lambda {|vm| vm.push(self.to_s.downcase.freeze) })
|
268
|
+
|
269
|
+
# ["abCD"*] .to_lower* [] #Convert to lower case in place.
|
270
|
+
StringBuffer.create_shared_method('.to_lower*', TosSpec, [],
|
271
|
+
&lambda {|vm| self.downcase! })
|
227
272
|
|
228
273
|
# ["stressed"] .reverse ["desserts"]
|
229
274
|
String.create_shared_method('.reverse', TosSpec, [],
|
230
|
-
&lambda {|vm| vm.push(self.reverse); })
|
275
|
+
&lambda {|vm| vm.push(self.to_s.reverse.freeze); })
|
276
|
+
|
277
|
+
# ["stressed"*] .reverse* [] #Reverse the string in place.
|
278
|
+
StringBuffer.create_shared_method('.reverse*', TosSpec, [],
|
279
|
+
&lambda {|vm| self.reverse! })
|
231
280
|
|
232
281
|
# ["abc\\ndef\\n123"] .lines [["abc", "def", "123"]]
|
233
282
|
String.create_shared_method('.lines', TosSpec, [],
|