lisp-interpreter 0.1.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.
@@ -0,0 +1,272 @@
1
+ # Optimization module
2
+ module Optimize
3
+ def fold_values_helper(other)
4
+ other = other.map { |t| find_list_function_value [t] }
5
+ (equalize_lists other).transpose
6
+ end
7
+
8
+ def get_fold_values(other)
9
+ values = find_all_values other
10
+ raise 'Incorrect number of arguments' if values.empty?
11
+ x = values[0]
12
+ y = fold_values_helper values[1..-1]
13
+ [x, y]
14
+ end
15
+
16
+ def rm_from_in_scope(scope, idx, def_vars)
17
+ i = find_bracket_idx scope, idx
18
+ def_vars[scope[idx + 2].to_s] = scope[idx + 3..i - 1]
19
+ scope.slice!(idx..i)
20
+ [i + 1, scope, def_vars]
21
+ end
22
+
23
+ def inner_scope_replace(scope, vars)
24
+ scope.each_with_index do |t, i|
25
+ scope[i] = vars[t.to_s] if vars.key? t.to_s
26
+ end
27
+ scope.flatten
28
+ end
29
+
30
+ def fetch_inner_scope(scope, idx = 0, def_vars = {})
31
+ until idx >= scope.size
32
+ if scope[idx] == 'define'
33
+ idx, scope, def_vars = rm_from_in_scope scope, idx - 1, def_vars
34
+ else
35
+ idx += 1
36
+ end
37
+ end
38
+ inner_scope_replace scope, def_vars
39
+ end
40
+
41
+ def filter_helper(func, values)
42
+ result =
43
+ if func.is_a? Proc
44
+ values.select { |t| func.call(*t) == '#t' }
45
+ else
46
+ values.select { |t| (send func, [t]) == '#t' }
47
+ end
48
+ build_list result
49
+ end
50
+
51
+ def apply_helper(func, values)
52
+ return func.call(*values) if func.is_a? Proc
53
+ send func, values
54
+ end
55
+
56
+ def call_compose(other)
57
+ tmp = ['(', *other[1..-1]]
58
+ idx = find_bracket_idx tmp, 0
59
+ funcs = find_all_values tmp[1..idx - 1]
60
+ value, = find_next_value tmp[idx + 1..-1]
61
+ funcs.reverse.each do |t|
62
+ value = calc_input_val ['(', t, value.to_s, ')']
63
+ end
64
+ value
65
+ end
66
+
67
+ def build_compose_expr(funcs)
68
+ expr = ['(', 'x', ')']
69
+ funcs.each do |f|
70
+ expr << '('
71
+ expr << f
72
+ end
73
+ expr << 'x'
74
+ funcs.size.times { expr << ')' }
75
+ expr
76
+ end
77
+
78
+ def do_not_call_compose(other)
79
+ funcs = find_all_values other
80
+ raise 'Incorrect data type' if funcs.any? { |t| t.to_s.number? }
81
+ expr = build_compose_expr funcs
82
+ proc_lambda expr
83
+ end
84
+ end
85
+
86
+ # FunctionalScheme helper
87
+ module FunctionalSchemeHelper
88
+ include Optimize
89
+ def foldl_helper(func, accum, lst)
90
+ return accum if lst.empty?
91
+ value = func.call(*lst[0], accum.to_s) if func.is_a? Proc
92
+ value = send func, [*lst[0], accum] if value.nil?
93
+ foldl_helper func, value.to_s, lst[1..-1]
94
+ end
95
+
96
+ def foldr_helper(func, accum, lst)
97
+ return accum if lst.empty?
98
+ value = foldr_helper func, accum, lst[1..-1]
99
+ return func.call(*lst[0], value.to_s) if func.is_a? Proc
100
+ send func, [*lst[0], value.to_s]
101
+ end
102
+
103
+ def equalize_lists(other)
104
+ min = other.map(&:size).min
105
+ other.map { |t| t[0..min - 1] }
106
+ end
107
+
108
+ def member_helper(to_check, values)
109
+ return '#f' unless values.include? to_check
110
+ idx = values.index(to_check)
111
+ build_list values[idx..-1]
112
+ end
113
+
114
+ def find_params_lambda(other)
115
+ raise 'Unbound symbol ' + other.to_s if other[0] != '('
116
+ idx = find_bracket_idx other, 0
117
+ [other[1..idx - 1], other[idx + 1..-1]]
118
+ end
119
+
120
+ def eval_lambda(other)
121
+ idx = find_bracket_idx other.unshift('('), 0
122
+ to_eval = other[1..idx - 1]
123
+ (proc_lambda to_eval).call(*other[idx + 1..-1])
124
+ end
125
+
126
+ def proc_lambda_helper(other, params, args)
127
+ args = arg_finder args
128
+ raise 'Incorrect number of arguments' unless params.size == args.size
129
+ define_func_helper other.dup, params.dup, args
130
+ end
131
+
132
+ def proc_lambda(other)
133
+ params, other = find_params_lambda other
134
+ other = fetch_inner_scope other
135
+ to_return = other[0..1].join == '(compose' && params.empty?
136
+ return calc_input_val other if to_return
137
+ proc = proc do |*args|
138
+ proc_lambda_helper other, params, args
139
+ end
140
+ proc
141
+ end
142
+
143
+ def fetch_define(other)
144
+ if other[0] == '('
145
+ define_function other
146
+ else
147
+ define_var other[0].to_s, (find_all_values other[1..-1])
148
+ end
149
+ end
150
+
151
+ def define_var(var, values)
152
+ raise 'Incorrect number of arguments' if values.size != 1
153
+ raise 'Invalid variable name' unless valid_var_name var
154
+ set_var_helper var, values[0]
155
+ end
156
+
157
+ def set_values_define(other, params, args)
158
+ args = [args] unless args.is_a? Array
159
+ other.each_with_index do |t, idx|
160
+ if params.include? t
161
+ i = params.index t
162
+ other[idx] = args[i]
163
+ end
164
+ end
165
+ other
166
+ end
167
+
168
+ def define_func_helper(other, params, args)
169
+ temp = set_values_define other, params, args
170
+ calc_input_val temp
171
+ end
172
+
173
+ def arg_finder_helper(name, args)
174
+ if !name.nil?
175
+ args = args[1..-1]
176
+ [name, args]
177
+ else
178
+ find_next_value args
179
+ end
180
+ end
181
+
182
+ def arg_finder(args)
183
+ result = []
184
+ until args.empty?
185
+ name = predefined_method_caller [args[0]]
186
+ temp, args = arg_finder_helper name, args
187
+ result << temp
188
+ end
189
+ result
190
+ end
191
+
192
+ def define_function(other)
193
+ idx = find_bracket_idx other, 0
194
+ name, *params = other[1..idx - 1]
195
+ build_fn = ['(', 'lambda', '(', *params, ')', *other[idx + 1..-1], ')']
196
+ define_var name, (find_all_values build_fn)
197
+ end
198
+ end
199
+
200
+ # Functional programming main functions
201
+ module FunctionalScheme
202
+ include FunctionalSchemeHelper
203
+ def foldl(other)
204
+ raise 'Incorrect number of parameters' if other.size < 2
205
+ func, other = valid_function other
206
+ val_one, val_two = get_fold_values other
207
+ foldl_helper func, val_one, val_two
208
+ end
209
+
210
+ def foldr(other)
211
+ raise 'Incorrect number of parameters' if other.size < 2
212
+ func, other = valid_function other
213
+ val_one, val_two = get_fold_values other
214
+ foldr_helper func, val_one, val_two
215
+ end
216
+
217
+ def filter(other)
218
+ raise 'Incorrect number of parameters' if other.size < 2
219
+ func, other = valid_function other
220
+ raise 'Incorrect number of parameters' if other.empty?
221
+ values = find_all_values other
222
+ values = find_list_function_value [values[0]]
223
+ filter_helper func, values
224
+ end
225
+
226
+ def member(other)
227
+ raise 'Incorrect number of arguments' unless other.size == 2
228
+ to_check = other[0]
229
+ split_val = split_list_string other[1]
230
+ raise 'Invalid argument' unless split_val.pair? || split_val.list?
231
+ values = find_all_values split_val[2..-2]
232
+ member_helper to_check, values
233
+ end
234
+
235
+ def remove(other)
236
+ raise 'Incorrect number of arguments' unless other.size == 2
237
+ to_remove = other[0]
238
+ values = find_list_function_value [other[1]]
239
+ values.delete_at(values.index(to_remove) || values.length)
240
+ build_list values
241
+ end
242
+
243
+ def apply(other)
244
+ raise 'Incorrect number of arguments' if other.nil? || other.empty?
245
+ func, other = valid_function other
246
+ values = find_all_values other
247
+ *vs, lst = values
248
+ raise 'Incorrect data type' unless lst.list?
249
+ (find_list_function_value [lst]).each { |t| vs << t }
250
+ apply_helper func, vs
251
+ end
252
+
253
+ def compose(other)
254
+ if other[0] != 'compose'
255
+ do_not_call_compose other
256
+ else
257
+ call_compose other
258
+ end
259
+ end
260
+
261
+ def lambda(other)
262
+ if other[0] == 'lambda'
263
+ eval_lambda other[1..-1]
264
+ else
265
+ proc_lambda other
266
+ end
267
+ end
268
+
269
+ def define(other)
270
+ fetch_define other
271
+ end
272
+ end
@@ -0,0 +1,162 @@
1
+ # Helper functions for SchemeLists
2
+ module SchemeListsHelper
3
+ def evaluate_list(tokens, no_quotes)
4
+ find_all_values_list_evaluate tokens, no_quotes
5
+ end
6
+
7
+ def no_eval_list(tokens, no_quotes = false)
8
+ result = []
9
+ until tokens.empty?
10
+ value, tokens = build_next_value_as_string tokens
11
+ value = value[1..-2] if no_quotes && (check_for_string value.to_s)
12
+ result << value
13
+ end
14
+ result
15
+ end
16
+
17
+ def find_to_evaluate_or_not(tokens, no_quotes = false)
18
+ if tokens[0..1].join == '(list'
19
+ evaluate_list tokens[2..-2], no_quotes
20
+ elsif tokens[0..1].join == '(cons'
21
+ result = cons tokens[2..-2]
22
+ result[2..-2].split(' ')
23
+ else
24
+ no_eval_list tokens[2..-2], no_quotes
25
+ end
26
+ end
27
+
28
+ def find_idx_for_list(tokens)
29
+ if tokens[0] == '('
30
+ find_bracket_idx tokens, 0
31
+ elsif tokens[1] == '('
32
+ find_bracket_idx tokens, 1
33
+ end
34
+ end
35
+
36
+ def find_all_values_list_evaluate(tokens, no_quotes = false)
37
+ result = []
38
+ until tokens.empty?
39
+ x, tokens = find_next_value tokens
40
+ x = x[1..-2] if no_quotes && (check_for_string x.to_s)
41
+ result << x
42
+ end
43
+ result
44
+ end
45
+
46
+ def build_list(values)
47
+ '\'(' + values.join(' ') + ')'
48
+ end
49
+
50
+ def build_cons_from_list(values)
51
+ spacer = values[1].size == 3 ? '' : ' '
52
+ values[0].to_s + spacer + values[1][2..-2].to_s
53
+ end
54
+
55
+ def cons_helper(values)
56
+ result =
57
+ if values[1].to_s[0..1] == '\'('
58
+ build_cons_from_list values
59
+ else
60
+ values[0].to_s + ' . ' + values[1].to_s
61
+ end
62
+ '\'(' + result + ')'
63
+ end
64
+
65
+ def get_cons_values(tokens)
66
+ result = get_k_arguments tokens, false, 2
67
+ raise 'Too little arguments' if result.size != 2
68
+ result
69
+ end
70
+
71
+ def split_list_string(list)
72
+ result = list.split(/(\(|\)|\.)|\ /)
73
+ result.delete('')
74
+ result
75
+ end
76
+
77
+ def find_list_function_value(other)
78
+ raise 'Incorrect number of arguments' if other.size != 1
79
+ raise 'Invalid data type' unless other[0].list?
80
+ split_list_as_string other[0].to_s
81
+ end
82
+
83
+ def split_list_as_string(list_as_string)
84
+ split_value = split_list_string list_as_string.to_s
85
+ no_eval_list split_value[2..-2]
86
+ end
87
+
88
+ def car_cdr_values(other)
89
+ raise 'Incorrect number of arguments' if other.size != 1
90
+ return find_list_function_value other if other[0].list?
91
+ (split_list_string other[0].to_s)[2..-2] if other[0].pair?
92
+ end
93
+
94
+ def map_helper(lst, func)
95
+ return lst.map { |t| func.call(*t) } if func.is_a? Proc
96
+ lst.map { |t| send func, t }
97
+ end
98
+ end
99
+
100
+ # Scheme lists module
101
+ module SchemeLists
102
+ include SchemeListsHelper
103
+ def cons(other)
104
+ raise 'Incorrect number of arguments' if other.size != 2
105
+ cons_helper other
106
+ end
107
+
108
+ def list(other)
109
+ build_list other
110
+ end
111
+
112
+ def car(other)
113
+ value = car_cdr_values other
114
+ raise 'Cannot apply car on ' + other[0].to_s if value.nil? || value.empty?
115
+ value.shift
116
+ end
117
+
118
+ def cdr(other)
119
+ value = car_cdr_values other
120
+ raise 'Cannot apply cdr on ' + other[0].to_s if value.nil? || value.empty?
121
+ idx = value[1] == '.' ? 2 : 1
122
+ build_list value[idx..-1]
123
+ end
124
+
125
+ def list?(other)
126
+ raise 'Incorrect number of arguments' if other.size != 1
127
+ other[0].to_s.list? ? '#t' : '#f'
128
+ end
129
+
130
+ def pair?(other)
131
+ raise 'Incorrect number of arguments' if other.size != 1
132
+ other[0].to_s.pair? ? '#t' : '#f'
133
+ end
134
+
135
+ def null?(other)
136
+ raise 'Incorrect number of arguments' if other.size != 1
137
+ return '#f' unless other[0].to_s.list?
138
+ other[0].to_s.size == 3 ? '#t' : '#f'
139
+ end
140
+
141
+ def length(other)
142
+ (find_list_function_value other).size
143
+ end
144
+
145
+ def reverse(other)
146
+ value = find_list_function_value other
147
+ build_list value.reverse
148
+ end
149
+
150
+ def map(other)
151
+ func, other = valid_function other
152
+ lst = find_all_values other
153
+ lst = lst.map { |t| find_list_function_value [t] }
154
+ lst = (equalize_lists lst).transpose
155
+ build_list map_helper lst, func
156
+ end
157
+
158
+ def shuffle(other)
159
+ values = find_list_function_value other
160
+ build_list values.shuffle
161
+ end
162
+ end
@@ -0,0 +1,161 @@
1
+ # Helper functions for SchemeNumbers
2
+ module SchemeNumbersHelper
3
+ def get_one_arg_function(other)
4
+ raise 'Incorrect number of arguments' if other.size != 1
5
+ raise 'Invalid data type' unless check_for_number other[0]
6
+ other[0].to_num
7
+ end
8
+
9
+ def find_idx_numerators(other)
10
+ other[0] == '(' ? (find_bracket_idx other, 0) + 1 : 1
11
+ end
12
+
13
+ def num_denom_helper(other)
14
+ raise 'Incorrect number of arguments' if other.empty?
15
+ if other.size == 1
16
+ other = other[0].split('/')
17
+ else
18
+ _, temp = find_next_value other
19
+ raise 'Incorrect number of arguments' unless temp[0] == '/' || temp.empty?
20
+ i = find_idx_numerators other
21
+ other.delete_at(i)
22
+ end
23
+ other
24
+ end
25
+
26
+ def get_num_denom(other)
27
+ num, other = find_next_value other
28
+ raise 'Invalid data type' unless check_for_number num
29
+ return [num, 1] if other.empty?
30
+ denom, other = find_next_value other
31
+ raise 'Incorrect number of arguments' unless other.empty?
32
+ [num, denom]
33
+ end
34
+
35
+ def compare_value_arithmetic(other, oper)
36
+ raise 'Incorrect number of arguments' if other.size < 2
37
+ other = convert_to_num other
38
+ result = other.each_cons(2).all? { |x, y| x.public_send oper, y }
39
+ result ? '#t' : '#f'
40
+ end
41
+
42
+ def convert_to_num(other)
43
+ other.each do |t|
44
+ raise 'Invalid data type' unless check_for_number t
45
+ end
46
+ other.map(&:to_num)
47
+ end
48
+
49
+ def divide_special_convert(other)
50
+ other = convert_to_num other
51
+ return [0] if other.size == 1 && other[0] == 0.0
52
+ other
53
+ end
54
+
55
+ def divide_number(a, b)
56
+ return a / b if (a / b).to_i.to_f == a / b.to_f
57
+ a / b.to_f
58
+ end
59
+ end
60
+
61
+ # Scheme numbers module
62
+ module SchemeNumbers
63
+ include SchemeNumbersHelper
64
+
65
+ def <(other)
66
+ compare_value_arithmetic other, '<'
67
+ end
68
+
69
+ def >(other)
70
+ compare_value_arithmetic other, '>'
71
+ end
72
+
73
+ def <=(other)
74
+ compare_value_arithmetic other, '<='
75
+ end
76
+
77
+ def >=(other)
78
+ compare_value_arithmetic other, '>='
79
+ end
80
+
81
+ def +(other)
82
+ other = convert_to_num other
83
+ other.reduce(0, :+)
84
+ end
85
+
86
+ def -(other)
87
+ return 0 if other.empty?
88
+ other = convert_to_num other
89
+ return -other[0] if other.size == 1
90
+ other[0] + other[1..-1].reduce(0, :-)
91
+ end
92
+
93
+ def *(other)
94
+ other = convert_to_num other
95
+ other.reduce(1, :*)
96
+ end
97
+
98
+ def /(other)
99
+ raise 'Incorrect number of arguments' if other.empty?
100
+ other = divide_special_convert other
101
+ return (divide_number 1, other[0].to_num) if other.size == 1
102
+ other[1..-1].inject(other[0]) { |res, t| divide_number res, t }
103
+ end
104
+
105
+ def quotient(other)
106
+ raise 'Incorrect number of arguments' if other.size != 2
107
+ x, y = convert_to_num other
108
+ result = divide_number x, y
109
+ result < 0 ? result.ceil : result.floor
110
+ end
111
+
112
+ def remainder(other)
113
+ raise 'Incorrect number of arguments' if other.size != 2
114
+ x, y = convert_to_num other
115
+ (x.abs % y.abs) * (x / x.abs)
116
+ end
117
+
118
+ def modulo(other)
119
+ raise 'Incorrect number of arguments' if other.size != 2
120
+ x, y = convert_to_num other
121
+ x.modulo y
122
+ end
123
+
124
+ def numerator(other)
125
+ other = num_denom_helper other
126
+ result = (get_num_denom other)[0]
127
+ raise 'Invalid data type' unless check_for_number result
128
+ result.to_num
129
+ end
130
+
131
+ def denominator(other)
132
+ other = num_denom_helper other
133
+ result = (get_num_denom other)[1]
134
+ raise 'Invalid data type' unless check_for_number result
135
+ result.to_num
136
+ end
137
+
138
+ def abs(other)
139
+ (get_one_arg_function other).abs
140
+ end
141
+
142
+ def add1(other)
143
+ (get_one_arg_function other) + 1
144
+ end
145
+
146
+ def sub1(other)
147
+ (get_one_arg_function other) - 1
148
+ end
149
+
150
+ def min(other)
151
+ raise 'Incorrect number of arguments' if other.empty?
152
+ other = convert_to_num other
153
+ other.min
154
+ end
155
+
156
+ def max(other)
157
+ raise 'Incorrect number of arguments' if other.empty?
158
+ other = convert_to_num other
159
+ other.max
160
+ end
161
+ end