forthic 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/CLAUDE.md +74 -0
- data/Guardfile +3 -3
- data/Rakefile +1 -1
- data/lib/forthic/forthic_error.rb +1 -2
- data/lib/forthic/forthic_module.rb +10 -9
- data/lib/forthic/global_module.rb +321 -334
- data/lib/forthic/interpreter.rb +204 -104
- data/lib/forthic/token.rb +1 -2
- data/lib/forthic/tokenizer.rb +3 -3
- data/lib/forthic/variable.rb +1 -1
- data/lib/forthic/version.rb +1 -1
- data/lib/forthic/words/definition_word.rb +15 -17
- data/lib/forthic/words/end_array_word.rb +3 -3
- data/lib/forthic/words/end_module_word.rb +2 -2
- data/lib/forthic/words/imported_word.rb +3 -3
- data/lib/forthic/words/map_word.rb +5 -5
- data/lib/forthic/words/module_memo_bang_at_word.rb +3 -3
- data/lib/forthic/words/module_memo_bang_word.rb +3 -3
- data/lib/forthic/words/module_memo_word.rb +2 -2
- data/lib/forthic/words/module_word.rb +3 -3
- data/lib/forthic/words/push_value_word.rb +3 -3
- data/lib/forthic/words/start_module_word.rb +6 -6
- data/lib/forthic/words/word.rb +1 -1
- data/lib/forthic.rb +19 -19
- metadata +7 -3
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "time"
|
4
|
+
require "json"
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
require_relative
|
6
|
+
require_relative "forthic_module"
|
7
|
+
require_relative "forthic_error"
|
8
|
+
require_relative "words/word"
|
9
|
+
require_relative "words/push_value_word"
|
10
|
+
require_relative "words/map_word"
|
11
|
+
require_relative "tokenizer"
|
12
|
+
require_relative "code_location"
|
13
13
|
|
14
14
|
module Forthic
|
15
15
|
class GlobalModule < ForthicModule
|
@@ -26,7 +26,7 @@ module Forthic
|
|
26
26
|
comparator: nil,
|
27
27
|
push_rest: nil,
|
28
28
|
depth: nil,
|
29
|
-
interps: 1
|
29
|
+
interps: 1
|
30
30
|
})
|
31
31
|
|
32
32
|
@literal_handlers = [
|
@@ -34,7 +34,7 @@ module Forthic
|
|
34
34
|
method(:to_float),
|
35
35
|
method(:to_literal_date),
|
36
36
|
method(:to_time),
|
37
|
-
method(:to_int)
|
37
|
+
method(:to_int)
|
38
38
|
]
|
39
39
|
|
40
40
|
# --------------------------------------------------
|
@@ -203,11 +203,10 @@ module Forthic
|
|
203
203
|
# --------------------------------------------------
|
204
204
|
# Ruby-specific words
|
205
205
|
add_module_word(">SYM", method(:word_to_SYM))
|
206
|
-
|
207
206
|
end
|
208
207
|
|
209
208
|
def find_word(name)
|
210
|
-
result = super
|
209
|
+
result = super
|
211
210
|
result ||= find_literal_word(name)
|
212
211
|
result
|
213
212
|
end
|
@@ -229,14 +228,18 @@ module Forthic
|
|
229
228
|
end
|
230
229
|
|
231
230
|
def to_int(str_val)
|
232
|
-
|
233
|
-
|
231
|
+
Integer(str_val)
|
232
|
+
rescue
|
233
|
+
nil
|
234
234
|
end
|
235
235
|
|
236
236
|
def to_float(str_val)
|
237
237
|
return nil unless str_val.include?(".")
|
238
|
-
|
239
|
-
|
238
|
+
begin
|
239
|
+
Float(str_val)
|
240
|
+
rescue
|
241
|
+
nil
|
242
|
+
end
|
240
243
|
end
|
241
244
|
|
242
245
|
def to_literal_date(str_val)
|
@@ -246,8 +249,7 @@ module Forthic
|
|
246
249
|
year = match[1].to_i
|
247
250
|
month = match[2].to_i
|
248
251
|
day = match[3].to_i
|
249
|
-
|
250
|
-
result
|
252
|
+
Date.new(year, month, day)
|
251
253
|
end
|
252
254
|
|
253
255
|
def to_time(str_val)
|
@@ -259,8 +261,7 @@ module Forthic
|
|
259
261
|
return nil if hours > 23 || minutes >= 60
|
260
262
|
|
261
263
|
result = Time.now
|
262
|
-
|
263
|
-
result
|
264
|
+
Time.new(result.year, result.month, result.day, hours, minutes, 0)
|
264
265
|
end
|
265
266
|
|
266
267
|
# Convenience function to create element word handlers
|
@@ -282,7 +283,7 @@ module Forthic
|
|
282
283
|
varnames = interp.stack_pop
|
283
284
|
module_ = interp.cur_module
|
284
285
|
varnames.each do |v|
|
285
|
-
if
|
286
|
+
if /__.*/.match?(v)
|
286
287
|
raise ForthicError.new(
|
287
288
|
"global_module-696",
|
288
289
|
"word_VARIABLES: variable names cannot begin with '__': '#{v}'",
|
@@ -365,7 +366,6 @@ module Forthic
|
|
365
366
|
interp.stack_push(result)
|
366
367
|
end
|
367
368
|
|
368
|
-
|
369
369
|
# ( rec value field -- rec )
|
370
370
|
def word_l_REC_bang(interp)
|
371
371
|
field = interp.stack_pop
|
@@ -471,10 +471,10 @@ module Forthic
|
|
471
471
|
end
|
472
472
|
|
473
473
|
result = if container.is_a?(Array)
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
474
|
+
new_to_old.keys.sort.map { |k| container[new_to_old[k]] }
|
475
|
+
else
|
476
|
+
new_to_old.each_with_object({}) { |(new_key, old_key), res| res[new_key] = container[old_key] }
|
477
|
+
end
|
478
478
|
|
479
479
|
interp.stack_push(result)
|
480
480
|
end
|
@@ -488,10 +488,10 @@ module Forthic
|
|
488
488
|
container ||= []
|
489
489
|
|
490
490
|
values = if container.is_a?(Array)
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
491
|
+
container
|
492
|
+
else
|
493
|
+
container.values
|
494
|
+
end
|
495
495
|
|
496
496
|
result = {}
|
497
497
|
values.each do |v|
|
@@ -510,10 +510,10 @@ module Forthic
|
|
510
510
|
container ||= []
|
511
511
|
|
512
512
|
values = if container.is_a?(Array)
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
513
|
+
container
|
514
|
+
else
|
515
|
+
container.values
|
516
|
+
end
|
517
517
|
|
518
518
|
result = {}
|
519
519
|
values.each do |v|
|
@@ -540,15 +540,15 @@ module Forthic
|
|
540
540
|
|
541
541
|
container = interp.stack_pop
|
542
542
|
|
543
|
-
flags = interp.get_flags(
|
543
|
+
flags = interp.get_flags(module_id)
|
544
544
|
|
545
545
|
container ||= []
|
546
546
|
|
547
547
|
keys, values = if container.is_a?(Array)
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
548
|
+
[Array.new(container.size) { |i| i }, container]
|
549
|
+
else
|
550
|
+
[container.keys, container.values]
|
551
|
+
end
|
552
552
|
|
553
553
|
result = {}
|
554
554
|
values.each_with_index do |value, i|
|
@@ -573,12 +573,12 @@ module Forthic
|
|
573
573
|
|
574
574
|
container ||= []
|
575
575
|
result = if container.is_a?(Array)
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
576
|
+
group_items(container, size)
|
577
|
+
else
|
578
|
+
keys = container.keys
|
579
|
+
key_groups = group_items(keys, size)
|
580
|
+
key_groups.map { |ks| extract_rec(container, ks) }
|
581
|
+
end
|
582
582
|
|
583
583
|
interp.stack_push(result)
|
584
584
|
end
|
@@ -616,7 +616,7 @@ module Forthic
|
|
616
616
|
forthic = interp.stack_pop
|
617
617
|
string_location = interp.get_string_location
|
618
618
|
items = interp.stack_pop
|
619
|
-
flags = interp.get_flags(
|
619
|
+
flags = interp.get_flags(module_id)
|
620
620
|
|
621
621
|
map_word = MapWord.new(items, forthic, string_location, flags)
|
622
622
|
map_word.execute(interp)
|
@@ -628,7 +628,7 @@ module Forthic
|
|
628
628
|
string_location = interp.get_string_location
|
629
629
|
|
630
630
|
items = interp.stack_pop
|
631
|
-
flags = interp.get_flags(
|
631
|
+
flags = interp.get_flags(module_id)
|
632
632
|
|
633
633
|
if !items
|
634
634
|
interp.stack_push(items)
|
@@ -690,10 +690,10 @@ module Forthic
|
|
690
690
|
container2 ||= []
|
691
691
|
|
692
692
|
result = if container2.is_a?(Array)
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
693
|
+
container1.map.with_index { |v, i| [v, container2[i]] }
|
694
|
+
else
|
695
|
+
container1.each_with_object({}) { |(k, v), res| res[k] = [v, container2[k]] }
|
696
|
+
end
|
697
697
|
|
698
698
|
interp.stack_push(result)
|
699
699
|
end
|
@@ -711,20 +711,20 @@ module Forthic
|
|
711
711
|
container2 ||= []
|
712
712
|
|
713
713
|
result = if container2.is_a?(Array)
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
714
|
+
container1.map.with_index do |v, i|
|
715
|
+
interp.stack_push(v)
|
716
|
+
interp.stack_push(container2[i])
|
717
|
+
interp.run(forthic, string_location)
|
718
|
+
interp.stack_pop
|
719
|
+
end
|
720
|
+
else
|
721
|
+
container1.each_with_object({}) do |(k, v), res|
|
722
|
+
interp.stack_push(v)
|
723
|
+
interp.stack_push(container2[k])
|
724
|
+
interp.run(forthic, string_location)
|
725
|
+
res[k] = interp.stack_pop
|
726
|
+
end
|
727
|
+
end
|
728
728
|
|
729
729
|
interp.stack_push(result)
|
730
730
|
end
|
@@ -737,10 +737,10 @@ module Forthic
|
|
737
737
|
container ||= []
|
738
738
|
|
739
739
|
result = if container.is_a?(Array)
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
740
|
+
container.each_index.to_a
|
741
|
+
else
|
742
|
+
container.keys
|
743
|
+
end
|
744
744
|
|
745
745
|
interp.stack_push(result)
|
746
746
|
end
|
@@ -753,10 +753,10 @@ module Forthic
|
|
753
753
|
container ||= []
|
754
754
|
|
755
755
|
result = if container.is_a?(Array)
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
756
|
+
container
|
757
|
+
else
|
758
|
+
container.values
|
759
|
+
end
|
760
760
|
|
761
761
|
interp.stack_push(result)
|
762
762
|
end
|
@@ -844,16 +844,16 @@ module Forthic
|
|
844
844
|
end
|
845
845
|
|
846
846
|
result = if container.is_a?(Array)
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
847
|
+
indexes.map { |i| i.nil? ? nil : container[i] }
|
848
|
+
else
|
849
|
+
keys = container.keys.sort
|
850
|
+
indexes.each_with_object({}) do |i, res|
|
851
|
+
next if i.nil?
|
852
852
|
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
853
|
+
k = keys[i]
|
854
|
+
res[k] = container[k]
|
855
|
+
end
|
856
|
+
end
|
857
857
|
|
858
858
|
interp.stack_push(result)
|
859
859
|
end
|
@@ -868,11 +868,11 @@ module Forthic
|
|
868
868
|
rcontainer ||= []
|
869
869
|
|
870
870
|
result = if rcontainer.is_a?(Array)
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
871
|
+
lcontainer - rcontainer
|
872
|
+
else
|
873
|
+
diff = lcontainer.keys - rcontainer.keys
|
874
|
+
diff.each_with_object({}) { |k, res| res[k] = lcontainer[k] }
|
875
|
+
end
|
876
876
|
|
877
877
|
interp.stack_push(result)
|
878
878
|
end
|
@@ -887,14 +887,14 @@ module Forthic
|
|
887
887
|
rcontainer ||= []
|
888
888
|
|
889
889
|
result = if rcontainer.is_a?(Array)
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
890
|
+
lcontainer & rcontainer
|
891
|
+
else
|
892
|
+
lkeys = lcontainer.keys
|
893
|
+
rkeys = rcontainer.keys
|
894
894
|
|
895
|
-
|
896
|
-
|
897
|
-
|
895
|
+
intersect = lkeys & rkeys
|
896
|
+
intersect.each_with_object({}) { |k, res| res[k] = lcontainer[k] }
|
897
|
+
end
|
898
898
|
|
899
899
|
interp.stack_push(result)
|
900
900
|
end
|
@@ -909,18 +909,18 @@ module Forthic
|
|
909
909
|
rcontainer ||= []
|
910
910
|
|
911
911
|
result = if rcontainer.is_a?(Array)
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
912
|
+
lcontainer | rcontainer
|
913
|
+
else
|
914
|
+
lkeys = lcontainer.keys
|
915
|
+
rkeys = rcontainer.keys
|
916
|
+
|
917
|
+
keys = lkeys | rkeys
|
918
|
+
keys.each_with_object({}) do |k, res|
|
919
|
+
val = lcontainer[k]
|
920
|
+
val = rcontainer[k] if val.nil?
|
921
|
+
res[k] = val
|
922
|
+
end
|
923
|
+
end
|
924
924
|
|
925
925
|
interp.stack_push(result)
|
926
926
|
end
|
@@ -932,7 +932,7 @@ module Forthic
|
|
932
932
|
string_location = interp.get_string_location
|
933
933
|
|
934
934
|
container = interp.stack_pop
|
935
|
-
flags = interp.get_flags(
|
935
|
+
flags = interp.get_flags(module_id)
|
936
936
|
|
937
937
|
if !container
|
938
938
|
interp.stack_push(container)
|
@@ -967,7 +967,7 @@ module Forthic
|
|
967
967
|
def word_TAKE(interp)
|
968
968
|
n = interp.stack_pop
|
969
969
|
container = interp.stack_pop
|
970
|
-
flags = interp.get_flags(
|
970
|
+
flags = interp.get_flags(module_id)
|
971
971
|
|
972
972
|
container ||= []
|
973
973
|
|
@@ -976,11 +976,11 @@ module Forthic
|
|
976
976
|
|
977
977
|
if container.is_a?(Array)
|
978
978
|
taken = container[0...n]
|
979
|
-
rest = container[n
|
979
|
+
rest = container[n..]
|
980
980
|
else
|
981
981
|
keys = container.keys.sort
|
982
982
|
taken_keys = keys[0...n]
|
983
|
-
rest_keys = keys[n
|
983
|
+
rest_keys = keys[n..]
|
984
984
|
taken = taken_keys.each_with_object({}) { |k, res| res[k] = container[k] }
|
985
985
|
rest = rest_keys.each_with_object({}) { |k, res| res[k] = container[k] }
|
986
986
|
end
|
@@ -1002,10 +1002,10 @@ module Forthic
|
|
1002
1002
|
|
1003
1003
|
result = nil
|
1004
1004
|
if container.is_a?(Array)
|
1005
|
-
result = container[n
|
1005
|
+
result = container[n..]
|
1006
1006
|
else
|
1007
1007
|
keys = container.keys.sort
|
1008
|
-
rest_keys = keys[n
|
1008
|
+
rest_keys = keys[n..]
|
1009
1009
|
result = rest_keys.each_with_object({}) { |k, res| res[k] = container[k] }
|
1010
1010
|
end
|
1011
1011
|
|
@@ -1049,12 +1049,10 @@ module Forthic
|
|
1049
1049
|
interp.stack_push(container)
|
1050
1050
|
return
|
1051
1051
|
end
|
1052
|
-
|
1053
|
-
|
1054
|
-
if container.is_a?(Array)
|
1055
|
-
result = container.shuffle
|
1052
|
+
result = if container.is_a?(Array)
|
1053
|
+
container.shuffle
|
1056
1054
|
else
|
1057
|
-
|
1055
|
+
container
|
1058
1056
|
end
|
1059
1057
|
|
1060
1058
|
interp.stack_push(result)
|
@@ -1066,7 +1064,7 @@ module Forthic
|
|
1066
1064
|
flag_string_position = interp.get_string_location
|
1067
1065
|
container = interp.stack_pop
|
1068
1066
|
|
1069
|
-
flags = interp.get_flags(
|
1067
|
+
flags = interp.get_flags(module_id)
|
1070
1068
|
comparator = flags[:comparator]
|
1071
1069
|
|
1072
1070
|
container ||= []
|
@@ -1075,15 +1073,14 @@ module Forthic
|
|
1075
1073
|
return
|
1076
1074
|
end
|
1077
1075
|
|
1078
|
-
|
1079
1076
|
# Figure out what to do
|
1080
1077
|
result = if comparator.is_a?(String)
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1078
|
+
sort_with_forthic(interp, comparator, flag_string_position, container)
|
1079
|
+
elsif comparator.nil?
|
1080
|
+
sort_without_comparator(container)
|
1081
|
+
else
|
1082
|
+
sort_with_key_func(container, comparator)
|
1083
|
+
end
|
1087
1084
|
|
1088
1085
|
interp.stack_push(result)
|
1089
1086
|
end
|
@@ -1142,17 +1139,17 @@ module Forthic
|
|
1142
1139
|
|
1143
1140
|
result = nil
|
1144
1141
|
if container.is_a?(Array)
|
1145
|
-
if container.length == 0
|
1146
|
-
|
1142
|
+
result = if container.length == 0
|
1143
|
+
nil
|
1147
1144
|
else
|
1148
|
-
|
1145
|
+
container[container.length - 1]
|
1149
1146
|
end
|
1150
1147
|
else
|
1151
1148
|
keys = container.keys.sort
|
1152
|
-
if keys.length == 0
|
1153
|
-
|
1149
|
+
result = if keys.length == 0
|
1150
|
+
nil
|
1154
1151
|
else
|
1155
|
-
|
1152
|
+
container[keys[keys.length - 1]]
|
1156
1153
|
end
|
1157
1154
|
end
|
1158
1155
|
|
@@ -1164,7 +1161,7 @@ module Forthic
|
|
1164
1161
|
def word_UNPACK(interp)
|
1165
1162
|
container = interp.stack_pop
|
1166
1163
|
|
1167
|
-
container
|
1164
|
+
container ||= []
|
1168
1165
|
|
1169
1166
|
if container.is_a?(Array)
|
1170
1167
|
container.each do |item|
|
@@ -1182,16 +1179,16 @@ module Forthic
|
|
1182
1179
|
# ( record -- record )
|
1183
1180
|
def word_FLATTEN(interp)
|
1184
1181
|
nested = interp.stack_pop
|
1185
|
-
flags = interp.get_flags(
|
1182
|
+
flags = interp.get_flags(module_id)
|
1186
1183
|
|
1187
1184
|
nested ||= []
|
1188
1185
|
depth = flags[:depth]
|
1189
1186
|
|
1190
1187
|
result = if nested.is_a?(Array)
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1188
|
+
flatten_array(nested, depth)
|
1189
|
+
else
|
1190
|
+
flatten_record(nested, depth, {}, [])
|
1191
|
+
end
|
1195
1192
|
|
1196
1193
|
interp.stack_push(result)
|
1197
1194
|
end
|
@@ -1208,7 +1205,7 @@ module Forthic
|
|
1208
1205
|
if container.is_a?(Array)
|
1209
1206
|
index = container.index(item)
|
1210
1207
|
# If index is nil or < 0, return nil
|
1211
|
-
result = index.nil? || index < 0 ? nil : index
|
1208
|
+
result = (index.nil? || index < 0) ? nil : index
|
1212
1209
|
else
|
1213
1210
|
keys = container.keys
|
1214
1211
|
keys.each do |k|
|
@@ -1223,37 +1220,35 @@ module Forthic
|
|
1223
1220
|
interp.stack_push(result)
|
1224
1221
|
end
|
1225
1222
|
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1223
|
+
# ( array init forthic -- value )
|
1224
|
+
# ( record init forthic -- value )
|
1225
|
+
def word_REDUCE(interp)
|
1226
|
+
forthic = interp.stack_pop
|
1227
|
+
string_location = interp.get_string_location
|
1231
1228
|
|
1232
|
-
|
1233
|
-
|
1229
|
+
initial = interp.stack_pop
|
1230
|
+
container = interp.stack_pop
|
1234
1231
|
|
1235
|
-
|
1232
|
+
container ||= []
|
1236
1233
|
|
1237
|
-
|
1238
|
-
if container.is_a?(Array)
|
1239
|
-
interp.stack_push(initial)
|
1240
|
-
container.each do |item|
|
1241
|
-
interp.stack_push(item)
|
1242
|
-
interp.run(forthic, string_location)
|
1243
|
-
end
|
1244
|
-
result = interp.stack_pop
|
1245
|
-
else
|
1246
|
-
interp.stack_push(initial)
|
1247
|
-
container.each do |k, v|
|
1248
|
-
interp.stack_push(v)
|
1249
|
-
interp.run(forthic, string_location)
|
1250
|
-
end
|
1251
|
-
result = interp.stack_pop
|
1252
|
-
end
|
1234
|
+
interp.stack_push(initial)
|
1253
1235
|
|
1254
|
-
|
1236
|
+
if container.is_a?(Array)
|
1237
|
+
container.each do |item|
|
1238
|
+
interp.stack_push(item)
|
1239
|
+
interp.run(forthic, string_location)
|
1240
|
+
end
|
1241
|
+
else
|
1242
|
+
container.each do |k, v|
|
1243
|
+
interp.stack_push(v)
|
1244
|
+
interp.run(forthic, string_location)
|
1245
|
+
end
|
1255
1246
|
end
|
1256
1247
|
|
1248
|
+
result = interp.stack_pop
|
1249
|
+
|
1250
|
+
interp.stack_push(result)
|
1251
|
+
end
|
1257
1252
|
|
1258
1253
|
# ( a -- )
|
1259
1254
|
def word_POP(interp)
|
@@ -1428,7 +1423,7 @@ module Forthic
|
|
1428
1423
|
def word_DEFAULT(interp)
|
1429
1424
|
default_value = interp.stack_pop
|
1430
1425
|
value = interp.stack_pop
|
1431
|
-
result = value.nil? || value == "" ? default_value : value
|
1426
|
+
result = (value.nil? || value == "") ? default_value : value
|
1432
1427
|
interp.stack_push(result)
|
1433
1428
|
end
|
1434
1429
|
|
@@ -1466,14 +1461,13 @@ module Forthic
|
|
1466
1461
|
def word_to_FIXED(interp)
|
1467
1462
|
num_places = interp.stack_pop
|
1468
1463
|
value = interp.stack_pop
|
1469
|
-
result = value
|
1470
|
-
|
1471
|
-
result = ""
|
1464
|
+
result = if value.nil?
|
1465
|
+
""
|
1472
1466
|
elsif !value.is_a?(Numeric)
|
1473
|
-
|
1467
|
+
value
|
1474
1468
|
else
|
1475
1469
|
# Round value to num_places
|
1476
|
-
|
1470
|
+
value.round(num_places)
|
1477
1471
|
end
|
1478
1472
|
interp.stack_push(result.to_s)
|
1479
1473
|
end
|
@@ -1515,7 +1509,6 @@ module Forthic
|
|
1515
1509
|
end
|
1516
1510
|
end
|
1517
1511
|
|
1518
|
-
|
1519
1512
|
# ( time -- time )
|
1520
1513
|
def word_AM(interp)
|
1521
1514
|
time = interp.stack_pop
|
@@ -1549,24 +1542,21 @@ module Forthic
|
|
1549
1542
|
# ( obj -- time )
|
1550
1543
|
def word_to_TIME(interp)
|
1551
1544
|
obj = interp.stack_pop
|
1552
|
-
result =
|
1553
|
-
|
1554
|
-
result = obj
|
1545
|
+
result = if obj.is_a?(Time)
|
1546
|
+
obj
|
1555
1547
|
else
|
1556
|
-
|
1548
|
+
Time.parse(obj.to_s)
|
1557
1549
|
end
|
1558
1550
|
interp.stack_push(result)
|
1559
1551
|
end
|
1560
1552
|
|
1561
|
-
|
1562
1553
|
# ( obj -- date )
|
1563
1554
|
def word_to_DATE(interp)
|
1564
1555
|
obj = interp.stack_pop
|
1565
|
-
result =
|
1566
|
-
|
1567
|
-
result = obj
|
1556
|
+
result = if obj.is_a?(Date)
|
1557
|
+
obj
|
1568
1558
|
else
|
1569
|
-
|
1559
|
+
Date.parse(obj.to_s)
|
1570
1560
|
end
|
1571
1561
|
interp.stack_push(result)
|
1572
1562
|
end
|
@@ -1674,11 +1664,13 @@ module Forthic
|
|
1674
1664
|
numbers = [a, b]
|
1675
1665
|
end
|
1676
1666
|
|
1667
|
+
nil_found = numbers.any?(&:nil?)
|
1668
|
+
if nil_found
|
1669
|
+
interp.stack_push(nil)
|
1670
|
+
return
|
1671
|
+
end
|
1672
|
+
|
1677
1673
|
numbers.each do |num|
|
1678
|
-
if num.nil?
|
1679
|
-
interp.stack_push(nil)
|
1680
|
-
return
|
1681
|
-
end
|
1682
1674
|
result *= num
|
1683
1675
|
end
|
1684
1676
|
|
@@ -1883,7 +1875,6 @@ module Forthic
|
|
1883
1875
|
interp.stack_push(result)
|
1884
1876
|
end
|
1885
1877
|
|
1886
|
-
|
1887
1878
|
# ( vals required_vals -- bool )
|
1888
1879
|
def word_ALL(interp)
|
1889
1880
|
required_vals = interp.stack_pop
|
@@ -1899,11 +1890,10 @@ module Forthic
|
|
1899
1890
|
# ( item -- bool )
|
1900
1891
|
def word_to_BOOL(interp)
|
1901
1892
|
item = interp.stack_pop
|
1902
|
-
result =
|
1903
|
-
|
1904
|
-
result = false
|
1893
|
+
result = if item.nil? || item == "" || item == 0
|
1894
|
+
false
|
1905
1895
|
else
|
1906
|
-
|
1896
|
+
!!item
|
1907
1897
|
end
|
1908
1898
|
interp.stack_push(result)
|
1909
1899
|
end
|
@@ -1922,7 +1912,6 @@ module Forthic
|
|
1922
1912
|
interp.stack_push(result)
|
1923
1913
|
end
|
1924
1914
|
|
1925
|
-
|
1926
1915
|
# ( val start_ranges -- index )
|
1927
1916
|
def word_RANGE_INDEX(interp)
|
1928
1917
|
start_ranges = interp.stack_pop
|
@@ -1952,7 +1941,6 @@ module Forthic
|
|
1952
1941
|
interp.stack_push(result)
|
1953
1942
|
end
|
1954
1943
|
|
1955
|
-
|
1956
1944
|
# ( -- Infinity )
|
1957
1945
|
def word_INFINITY(interp)
|
1958
1946
|
interp.stack_push(Float::INFINITY)
|
@@ -2026,23 +2014,23 @@ module Forthic
|
|
2026
2014
|
|
2027
2015
|
# ( -- )
|
2028
2016
|
def word_bang_PUSH_ERROR(interp)
|
2029
|
-
interp.modify_flags(
|
2017
|
+
interp.modify_flags(module_id, {push_error: true})
|
2030
2018
|
end
|
2031
2019
|
|
2032
2020
|
# ( -- )
|
2033
2021
|
def word_bang_WITH_KEY(interp)
|
2034
|
-
interp.modify_flags(
|
2022
|
+
interp.modify_flags(module_id, {with_key: true})
|
2035
2023
|
end
|
2036
2024
|
|
2037
2025
|
# ( comparator -- )
|
2038
2026
|
def word_bang_COMPARATOR(interp)
|
2039
2027
|
comparator = interp.stack_pop
|
2040
|
-
interp.modify_flags(
|
2028
|
+
interp.modify_flags(module_id, {comparator: comparator})
|
2041
2029
|
end
|
2042
2030
|
|
2043
2031
|
# ( -- )
|
2044
2032
|
def word_bang_PUSH_REST(interp)
|
2045
|
-
interp.modify_flags(
|
2033
|
+
interp.modify_flags(module_id, {push_rest: true})
|
2046
2034
|
end
|
2047
2035
|
|
2048
2036
|
# ( depth -- )
|
@@ -2050,13 +2038,13 @@ module Forthic
|
|
2050
2038
|
# NOTE: `depth` of 0 is the same not having set depth
|
2051
2039
|
def word_bang_DEPTH(interp)
|
2052
2040
|
depth = interp.stack_pop
|
2053
|
-
interp.modify_flags(
|
2041
|
+
interp.modify_flags(module_id, {depth: depth})
|
2054
2042
|
end
|
2055
2043
|
|
2056
2044
|
# ( num_inteprs -- )
|
2057
2045
|
def word_bang_INTERPS(interp)
|
2058
2046
|
num_interps = interp.stack_pop
|
2059
|
-
interp.modify_flags(
|
2047
|
+
interp.modify_flags(module_id, {interps: num_interps})
|
2060
2048
|
end
|
2061
2049
|
|
2062
2050
|
# ( -- )
|
@@ -2082,11 +2070,11 @@ module Forthic
|
|
2082
2070
|
|
2083
2071
|
result = {
|
2084
2072
|
word_counts: [],
|
2085
|
-
timestamps: []
|
2073
|
+
timestamps: []
|
2086
2074
|
}
|
2087
2075
|
|
2088
2076
|
histogram.each do |val|
|
2089
|
-
rec = {
|
2077
|
+
rec = {word: val[:word], count: val[:count]}
|
2090
2078
|
result[:word_counts].push(rec)
|
2091
2079
|
end
|
2092
2080
|
|
@@ -2095,7 +2083,7 @@ module Forthic
|
|
2095
2083
|
rec = {
|
2096
2084
|
label: t[:label],
|
2097
2085
|
time_ms: t[:time_ms],
|
2098
|
-
delta: t[:time_ms] - prev_time
|
2086
|
+
delta: t[:time_ms] - prev_time
|
2099
2087
|
}
|
2100
2088
|
prev_time = t[:time_ms]
|
2101
2089
|
result[:timestamps].push(rec)
|
@@ -2104,7 +2092,6 @@ module Forthic
|
|
2104
2092
|
interp.stack_push(result)
|
2105
2093
|
end
|
2106
2094
|
|
2107
|
-
|
2108
2095
|
# ( string -- symbol )
|
2109
2096
|
def word_to_SYM(interp)
|
2110
2097
|
string = interp.stack_pop
|
@@ -2115,10 +2102,11 @@ module Forthic
|
|
2115
2102
|
# --------------------------------------------------
|
2116
2103
|
# Helpers
|
2117
2104
|
private
|
2105
|
+
|
2118
2106
|
def drill_for_value(rec, fields)
|
2119
2107
|
cur_rec = rec
|
2120
2108
|
fields.each do |f|
|
2121
|
-
if cur_rec.is_a?(Array)
|
2109
|
+
if cur_rec.is_a?(Array) || cur_rec.is_a?(Hash)
|
2122
2110
|
cur_rec = cur_rec[f]
|
2123
2111
|
else
|
2124
2112
|
return nil
|
@@ -2151,7 +2139,7 @@ module Forthic
|
|
2151
2139
|
result = nil
|
2152
2140
|
begin
|
2153
2141
|
interp.run(forthic, string_location)
|
2154
|
-
rescue
|
2142
|
+
rescue => e
|
2155
2143
|
result = e
|
2156
2144
|
end
|
2157
2145
|
result
|
@@ -2163,37 +2151,55 @@ module Forthic
|
|
2163
2151
|
res
|
2164
2152
|
end
|
2165
2153
|
|
2166
|
-
|
2167
|
-
|
2168
|
-
|
2169
|
-
|
2154
|
+
# Default sort
|
2155
|
+
def sort_without_comparator(container)
|
2156
|
+
# Separate nil values from non-nil values
|
2157
|
+
nils, non_nils = container.partition(&:nil?)
|
2170
2158
|
|
2171
|
-
|
2172
|
-
|
2173
|
-
|
2159
|
+
# Sort non_nils and append nils
|
2160
|
+
non_nils.sort + nils
|
2161
|
+
end
|
2162
|
+
|
2163
|
+
# Sort using a forthic string
|
2164
|
+
def sort_with_forthic(interp, forthic, flag_string_position, container)
|
2165
|
+
aug_array = make_aug_array(interp, forthic, flag_string_position, container)
|
2166
|
+
aug_array.sort! { |l, r| cmp_items(l, r) }
|
2167
|
+
de_aug_array(aug_array)
|
2168
|
+
end
|
2174
2169
|
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2170
|
+
def make_aug_array(interp, forthic, flag_string_position, vals)
|
2171
|
+
res = []
|
2172
|
+
vals.each do |val|
|
2173
|
+
interp.stack_push(val)
|
2174
|
+
interp.run(forthic, flag_string_position)
|
2175
|
+
aug_val = interp.stack_pop
|
2176
|
+
res.push([val, aug_val])
|
2180
2177
|
end
|
2178
|
+
res
|
2179
|
+
end
|
2181
2180
|
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
2189
|
-
|
2190
|
-
|
2181
|
+
def cmp_items(l, r)
|
2182
|
+
l_val = l[1]
|
2183
|
+
r_val = r[1]
|
2184
|
+
|
2185
|
+
if l_val < r_val
|
2186
|
+
-1
|
2187
|
+
elsif l_val > r_val
|
2188
|
+
1
|
2189
|
+
else
|
2190
|
+
0
|
2191
2191
|
end
|
2192
|
+
end
|
2192
2193
|
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2194
|
+
def de_aug_array(aug_vals)
|
2195
|
+
aug_vals.map { |aug_val| aug_val[0] }
|
2196
|
+
end
|
2196
2197
|
|
2198
|
+
# Sort with key func
|
2199
|
+
def sort_with_key_func(container, key_func)
|
2200
|
+
container.sort do |l, r|
|
2201
|
+
l_val = key_func.call(l)
|
2202
|
+
r_val = key_func.call(r)
|
2197
2203
|
if l_val < r_val
|
2198
2204
|
-1
|
2199
2205
|
elsif l_val > r_val
|
@@ -2202,140 +2208,121 @@ module Forthic
|
|
2202
2208
|
0
|
2203
2209
|
end
|
2204
2210
|
end
|
2211
|
+
end
|
2205
2212
|
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2213
|
+
def add_to_record_result(item, key, keys, result)
|
2214
|
+
new_key = (keys + [key]).join("\t")
|
2215
|
+
result[new_key] = item
|
2216
|
+
end
|
2209
2217
|
|
2210
|
-
|
2211
|
-
|
2212
|
-
|
2213
|
-
|
2214
|
-
|
2215
|
-
|
2216
|
-
-1
|
2217
|
-
elsif l_val > r_val
|
2218
|
-
1
|
2219
|
-
else
|
2220
|
-
0
|
2221
|
-
end
|
2218
|
+
def fully_flatten_record(record, res, keys)
|
2219
|
+
record.each do |k, item|
|
2220
|
+
if is_record(item)
|
2221
|
+
fully_flatten_record(item, res, keys + [k])
|
2222
|
+
else
|
2223
|
+
add_to_record_result(item, k, keys, res)
|
2222
2224
|
end
|
2223
2225
|
end
|
2226
|
+
res
|
2227
|
+
end
|
2224
2228
|
|
2225
|
-
|
2226
|
-
|
2227
|
-
result[new_key] = item
|
2228
|
-
end
|
2229
|
+
def flatten_record(record, depth, res, keys)
|
2230
|
+
return fully_flatten_record(record, res, keys) if depth.nil?
|
2229
2231
|
|
2230
|
-
|
2231
|
-
|
2232
|
-
|
2233
|
-
|
2234
|
-
|
2235
|
-
add_to_record_result(item, k, keys, res)
|
2236
|
-
end
|
2232
|
+
record.each do |k, item|
|
2233
|
+
if depth > 0 && is_record(item)
|
2234
|
+
flatten_record(item, depth - 1, res, keys + [k])
|
2235
|
+
else
|
2236
|
+
add_to_record_result(item, k, keys, res)
|
2237
2237
|
end
|
2238
|
-
res
|
2239
2238
|
end
|
2239
|
+
res
|
2240
|
+
end
|
2240
2241
|
|
2241
|
-
|
2242
|
-
|
2242
|
+
def flatten_array(array, depth)
|
2243
|
+
return array.flatten(depth) if depth
|
2244
|
+
array.flatten
|
2245
|
+
end
|
2243
2246
|
|
2244
|
-
|
2245
|
-
|
2246
|
-
|
2247
|
-
else
|
2248
|
-
add_to_record_result(item, k, keys, res)
|
2249
|
-
end
|
2250
|
-
end
|
2251
|
-
res
|
2252
|
-
end
|
2247
|
+
def is_record(obj)
|
2248
|
+
obj.is_a?(Hash) && !obj.empty?
|
2249
|
+
end
|
2253
2250
|
|
2254
|
-
|
2255
|
-
|
2256
|
-
|
2257
|
-
|
2251
|
+
def get_day_this_week(day_of_week)
|
2252
|
+
# Assume the start of the week is Monday and a day_of_week of 0 means a Monday
|
2253
|
+
# Get the current day of the week
|
2254
|
+
today = Date.today
|
2255
|
+
current_day_of_week = today.wday
|
2258
2256
|
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2257
|
+
# Return the date of the day_of_week
|
2258
|
+
today - (current_day_of_week - day_of_week)
|
2259
|
+
end
|
2262
2260
|
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2266
|
-
|
2267
|
-
current_day_of_week = today.wday
|
2261
|
+
# NOTE: Monday is the start of the week
|
2262
|
+
def normalize_day(day)
|
2263
|
+
day
|
2264
|
+
end
|
2268
2265
|
|
2269
|
-
|
2270
|
-
|
2271
|
-
|
2266
|
+
def compute_number_mean(numbers)
|
2267
|
+
sum = numbers.reduce(0) { |acc, num| acc + num }
|
2268
|
+
sum.to_f / numbers.length
|
2269
|
+
end
|
2272
2270
|
|
2273
|
-
|
2274
|
-
|
2275
|
-
|
2276
|
-
end
|
2271
|
+
def compute_non_number_mean(objects)
|
2272
|
+
non_null_objects = objects.reject { |obj| obj.nil? }
|
2273
|
+
res = Hash.new(0)
|
2277
2274
|
|
2278
|
-
|
2279
|
-
|
2280
|
-
|
2275
|
+
non_null_objects.each do |obj|
|
2276
|
+
obj_str = obj.is_a?(String) ? obj : obj.to_json
|
2277
|
+
res[obj_str] += 1
|
2281
2278
|
end
|
2282
2279
|
|
2283
|
-
|
2284
|
-
|
2285
|
-
res = Hash.new(0)
|
2286
|
-
|
2287
|
-
non_null_objects.each do |obj|
|
2288
|
-
obj_str = obj.is_a?(String) ? obj : obj.to_json
|
2289
|
-
res[obj_str] += 1
|
2290
|
-
end
|
2291
|
-
|
2292
|
-
res.each do |key, value|
|
2293
|
-
res[key] = value.to_f / non_null_objects.length
|
2294
|
-
end
|
2295
|
-
res
|
2280
|
+
res.each do |key, value|
|
2281
|
+
res[key] = value.to_f / non_null_objects.length
|
2296
2282
|
end
|
2283
|
+
res
|
2284
|
+
end
|
2297
2285
|
|
2298
|
-
|
2299
|
-
|
2300
|
-
|
2301
|
-
|
2302
|
-
|
2303
|
-
|
2304
|
-
end
|
2305
|
-
end
|
2306
|
-
|
2307
|
-
res.each do |key, values|
|
2308
|
-
res[key] = compute_mean(values)
|
2286
|
+
def compute_object_mean(records)
|
2287
|
+
res = {}
|
2288
|
+
records.each do |record|
|
2289
|
+
record.each do |key, value|
|
2290
|
+
res[key] ||= []
|
2291
|
+
res[key] << value
|
2309
2292
|
end
|
2310
|
-
res
|
2311
2293
|
end
|
2312
2294
|
|
2313
|
-
|
2314
|
-
|
2295
|
+
res.each do |key, values|
|
2296
|
+
res[key] = compute_mean(values)
|
2315
2297
|
end
|
2298
|
+
res
|
2299
|
+
end
|
2316
2300
|
|
2317
|
-
|
2318
|
-
|
2319
|
-
|
2301
|
+
def is_all_numbers(values)
|
2302
|
+
values.all? { |val| val.is_a?(Numeric) }
|
2303
|
+
end
|
2320
2304
|
|
2321
|
-
|
2322
|
-
|
2323
|
-
|
2305
|
+
def is_all_records(values)
|
2306
|
+
values.all? { |val| val.is_a?(Hash) }
|
2307
|
+
end
|
2324
2308
|
|
2325
|
-
|
2326
|
-
|
2327
|
-
|
2328
|
-
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2333
|
-
|
2334
|
-
|
2335
|
-
|
2309
|
+
def select_non_null_values(values)
|
2310
|
+
values.reject { |val| val.nil? }
|
2311
|
+
end
|
2312
|
+
|
2313
|
+
def compute_mean(values)
|
2314
|
+
result = nil
|
2315
|
+
if values.is_a?(Array)
|
2316
|
+
non_null_values = select_non_null_values(values)
|
2317
|
+
result = if is_all_numbers(non_null_values)
|
2318
|
+
compute_number_mean(non_null_values)
|
2319
|
+
elsif is_all_records(non_null_values)
|
2320
|
+
compute_object_mean(non_null_values)
|
2321
|
+
else
|
2322
|
+
compute_non_number_mean(non_null_values)
|
2336
2323
|
end
|
2337
|
-
result
|
2338
2324
|
end
|
2339
|
-
|
2325
|
+
result
|
2326
|
+
end
|
2340
2327
|
end
|
2341
|
-
end
|
2328
|
+
end
|