rbsiev 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,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rbsiev
4
+
5
+ module Primitives
6
+
7
+ module Comparison
8
+
9
+ def lt?(*args)
10
+ c_calc(:<, *args)
11
+ end
12
+
13
+ def le?(*args)
14
+ c_calc(:<=, *args)
15
+ end
16
+
17
+ def gt?(*args)
18
+ c_calc(:>, *args)
19
+ end
20
+
21
+ def ge?(*args)
22
+ c_calc(:>=, *args)
23
+ end
24
+
25
+ def same_value?(*args)
26
+ c_calc(:==, *args)
27
+ end
28
+
29
+ private
30
+
31
+ def c_calc(op, *args)
32
+ case args.size
33
+ when 0, 1
34
+ raise Error, "Too few arguments: got=%s" % scm_objs
35
+ when 2
36
+ args[0].send(op, args[1]) ? SCM_TRUE : SCM_FALSE
37
+ else
38
+ args[0].send(op, args[1]) and c_calc(op, *args[1..-1]) ? SCM_TRUE : SCM_FALSE
39
+ end
40
+ end
41
+
42
+ end # end of Comparison
43
+
44
+ end # end of Primitives
45
+
46
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rbsiev
4
+ module Primitives
5
+
6
+ module EmptyList
7
+
8
+ def null?(scm_obj)
9
+ scm_obj.kind_of?(Scmo::Object) && scm_obj.null?
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rbsiev
4
+ class Printer
5
+ def initialize
6
+ @verbose = false
7
+ end
8
+
9
+ attr_accessor :verbose
10
+
11
+ def print(value)
12
+ if @verbose
13
+ pp verbose
14
+ end
15
+ puts value.to_s
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rbsiev
4
+ class Procedure
5
+ def self.make_procedure(parameters, body, env)
6
+ if body.instance_of?(Symbol)
7
+ PrimitiveProcedure.new(nil, body, env)
8
+ else
9
+ CompoundProcedure.new(parameters, body, env)
10
+ end
11
+ end
12
+
13
+ def parameters(bare: false)
14
+ if bare
15
+ @parameters.map(&:literal)
16
+ else
17
+ @parameters
18
+ end
19
+ end
20
+
21
+ attr_reader :body
22
+ attr_reader :env
23
+
24
+ def type; nil; end
25
+ def apply(arguments); end
26
+
27
+ protected
28
+
29
+ def initialize(parameters, body, env)
30
+ @parameters = parameters
31
+ @body = body
32
+ @env = env
33
+ end
34
+ end
35
+
36
+ class PrimitiveProcedure < Procedure
37
+ def type; :procedure_primitive; end
38
+ def apply(arguments)
39
+ @env.send(@body, *arguments)
40
+ end
41
+ end
42
+
43
+ class CompoundProcedure < Procedure
44
+ def type; :procedure_compound; end
45
+ end
46
+
47
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "readline"
4
+
5
+ module Rbsiev
6
+
7
+ class Repl
8
+ def self.start(prompt: "REPL> ", verbose: false)
9
+ msg = Repl.new(prompt: prompt, verbose: verbose).loop
10
+ puts msg if msg
11
+ end
12
+
13
+ def initialize(prompt:, verbose: false)
14
+ @verbose = verbose
15
+ @prompt = prompt
16
+ @components = init_components
17
+ end
18
+
19
+ def loop
20
+ second_prompt = "." * (@prompt.length - 1) + " "
21
+
22
+ msg = Kernel.loop {
23
+ begin
24
+ source = read_source(second_prompt)
25
+ rescue EOFError => _
26
+ break "Bye!"
27
+ else
28
+ next if source.nil?
29
+ end
30
+
31
+ begin
32
+ @components.exec(source)
33
+ rescue Error => e
34
+ puts e.message
35
+ next
36
+ end
37
+ }
38
+ msg
39
+ end
40
+
41
+ private
42
+
43
+ def init_components
44
+ parser = Rubasteme.parser
45
+ evaluator = Evaluator.new
46
+ env = Rbsiev.setup_environment
47
+ printer = Printer.new
48
+
49
+ evaluator.verbose = @verbose
50
+ printer.verbose = @verbose
51
+
52
+ components = Components.new(parser, evaluator, printer, env)
53
+
54
+ func_map = {
55
+ load: lambda{|file| components.load(file)},
56
+ version: lambda{components.version},
57
+ }
58
+
59
+ procedures = []
60
+ func_map.each { |sym, func|
61
+ env.define_singleton_method(sym, func)
62
+ procedures << Procedure.make_procedure(nil, sym, env)
63
+ }
64
+ env = env.extend(func_map.keys.map(&:to_s), procedures)
65
+ components.env = env
66
+
67
+ components
68
+ end
69
+
70
+ def read_source(second_prompt = ">> ")
71
+ source = Readline::readline(@prompt, true)
72
+ raise EOFError if source.nil?
73
+
74
+ until match_parenthesis(source)
75
+ more_source = Readline::readline(second_prompt, true)
76
+ if more_source.nil?
77
+ source = nil
78
+ break
79
+ else
80
+ source += (more_source + " ")
81
+ end
82
+ end
83
+ source
84
+ end
85
+
86
+ def match_parenthesis(str)
87
+ count = count_characters(str, ["(", ")"])
88
+ count["("] == count[")"]
89
+ end
90
+
91
+ def count_characters(str, chars)
92
+ count = chars.to_h{|ch| [ch, 0]}
93
+ escaped = false
94
+ in_string = false
95
+ str.each_char { |rune|
96
+ case rune
97
+ when "\\"
98
+ escaped = !escaped if in_string
99
+ when '"'
100
+ in_string = !in_string unless escaped
101
+ escaped = false
102
+ when *chars
103
+ count[rune] += 1 unless in_string
104
+ else
105
+ escaped = false
106
+ end
107
+ }
108
+ count
109
+ end
110
+
111
+ end # end of Repl
112
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rbsiev
4
+ VERSION = "0.1.0"
5
+ RELEASE = "2021-06-08"
6
+ end
@@ -0,0 +1,313 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubasteme
4
+ module AST
5
+
6
+ # Miscellaneous functions to operate AST nodes.
7
+
8
+ module Misc
9
+
10
+ # For AST::IdentifierNode.
11
+
12
+ def identifier(ast_node)
13
+ if ast_node.respond_to?(:literal)
14
+ ast_node.literal
15
+ else
16
+ raise Error, "wrong type node: got=%s" % ast_node.to_a.to_s
17
+ end
18
+ end
19
+
20
+ # For AST::ListNode. They also accept an Array object as their
21
+ # arugment.
22
+
23
+ def empty_node?(obj)
24
+ check_list_type(obj)
25
+ obj.empty?
26
+ end
27
+
28
+ def last_node?(obj)
29
+ check_list_type(obj)
30
+ obj.size == 1
31
+ end
32
+
33
+ def first_node(obj)
34
+ check_list_type(obj)
35
+ obj[0]
36
+ end
37
+
38
+ def rest_nodes(obj)
39
+ check_list_type(obj)
40
+ obj[1..-1]
41
+ end
42
+
43
+ def list_elements(obj)
44
+ case obj
45
+ when ListNode
46
+ obj.elements
47
+ when Array
48
+ obj
49
+ else
50
+ raise Error, "wrong type node: expected=(Array or ListNode), got=%s" % obj.to_a.to_s
51
+ end
52
+ end
53
+
54
+ # for AST::FormalsNode
55
+
56
+ def parameters(ast_node)
57
+ check_type(:ast_formals, ast_node)
58
+ ast_node.map{|e| identifier(e)}
59
+ end
60
+
61
+ # For AST::BindingsNode
62
+
63
+ def last_binding?(ast_node)
64
+ last_node?(list_elements(ast_node))
65
+ end
66
+
67
+ def first_binding(ast_node)
68
+ first_node(ast_node)
69
+ end
70
+
71
+ def rest_bindings(ast_node)
72
+ make_bindings(rest_nodes(ast_node))
73
+ end
74
+
75
+ def bindings_specs(ast_node)
76
+ check_type(:ast_bindings, ast_node)
77
+ ast_node.elements
78
+ end
79
+
80
+ # Converter function.
81
+
82
+ def cond_to_if(ast_node)
83
+ check_type(:ast_cond, ast_node)
84
+ expand_clauses(ast_node.cond_clauses)
85
+ end
86
+
87
+ def sequence_to_node(ast_node)
88
+ check_type(:ast_sequence, ast_node)
89
+ if ast_node.empty?
90
+ EMPTY_LIST
91
+ elsif last_node?(ast_node)
92
+ first_node(ast_node)
93
+ else
94
+ make_begin(ast_node)
95
+ end
96
+ end
97
+
98
+ def let_to_combination(ast_node)
99
+ check_types([:ast_let, :ast_letrec, :ast_letrec_star], ast_node)
100
+
101
+ identifiers = []
102
+ operands = []
103
+
104
+ ast_node.bindings.each { |bind_spec|
105
+ identifiers << bind_spec.identifier
106
+ operands << bind_spec.expression
107
+ }
108
+
109
+ formals = make_formals(identifiers)
110
+ operator = make_lambda(formals, ast_node.body)
111
+
112
+ make_combination(operator, operands)
113
+ end
114
+
115
+ def let_star_to_nested_lets(bindings, body)
116
+ single_bindings = make_bindings([first_binding(bindings)])
117
+ if last_binding?(bindings)
118
+ make_let(single_bindings, body)
119
+ else
120
+ seq = make_sequence([let_star_to_nested_lets(rest_bindings(bindings), body)])
121
+ new_body = make_body(nil, seq)
122
+ make_let(single_bindings, new_body)
123
+ end
124
+ end
125
+
126
+ def do_to_named_let(ast_node, loop_identifier)
127
+ bind_specs = []
128
+ bind_specs_with_step = []
129
+ ast_node.iteration_bindings.each { |iter_spec|
130
+ spec = make_bind_spec(iter_spec.identifier, iter_spec.init)
131
+ if iter_spec.step
132
+ bind_specs_with_step << [spec, iter_spec.step]
133
+ else
134
+ bind_specs << spec
135
+ end
136
+ }
137
+
138
+ let_bindings = make_bindings(bind_specs_with_step.map{|e| e[0]})
139
+
140
+ test_and_do_result = ast_node.test_and_do_result
141
+
142
+ if_predicate = test_and_do_result.test
143
+ if_consequent = make_begin(rest_nodes(test_and_do_result))
144
+
145
+ sequence = []
146
+ sequence += ast_node.commands
147
+ sequence << make_combination(make_identifier(loop_identifier),
148
+ bind_specs_with_step.map{|e| e[1]})
149
+ if_alternative = make_begin(sequence)
150
+
151
+ if_node = make_if(if_predicate, if_consequent, if_alternative)
152
+ let_body = make_body(nil, make_sequence([if_node]))
153
+ let_node = make_let(let_bindings, let_body)
154
+ let_node.identifier = make_identifier(loop_identifier)
155
+
156
+ if bind_specs.empty?
157
+ let_node
158
+ else
159
+ let_body = make_body(nil, make_sequence([let_node]))
160
+ make_let(make_bindings(bind_specs), let_body)
161
+ end
162
+ end
163
+
164
+ # Construcing functions.
165
+
166
+ def make_identifier(literal)
167
+ Rubasteme::AST::instantiate(:ast_identifier, literal)
168
+ end
169
+
170
+ def make_lambda(formals, body)
171
+ check_type(:ast_body, body)
172
+ lambda_node = Rubasteme::AST.instantiate(:ast_lambda_expression, nil)
173
+ lambda_node.formals = formals
174
+ lambda_node.body = body
175
+ lambda_node
176
+ end
177
+
178
+ def make_begin(nodes)
179
+ begin_node = Rubasteme::AST.instantiate(:ast_begin, nil)
180
+ case nodes
181
+ when Rubasteme::AST::SequenceNode
182
+ begin_node.sequence = nodes
183
+ when Array
184
+ begin_node.sequence = make_sequence(nodes)
185
+ else
186
+ raise Error, "wrong type argument: expected= Array or Rubasteme::AST::SequenceNode, got=%s" % nodes.class
187
+ end
188
+ begin_node
189
+ end
190
+
191
+ def make_body(definitions, sequence)
192
+ body_node = Rubasteme::AST.instantiate(:ast_body, nil)
193
+
194
+ if definitions.nil?
195
+ definitions = Rubasteme::AST.instantiate(:ast_internal_definitions, nil)
196
+ end
197
+ if sequence.nil?
198
+ sequence = Rubasteme::ASt.instantiate(:ast_sequence, nil)
199
+ end
200
+
201
+ body_node.definitions = definitions
202
+ body_node.sequence = sequence
203
+
204
+ body_node
205
+ end
206
+
207
+ def make_sequence(nodes)
208
+ check_list_type(nodes)
209
+ seq_node = Rubasteme::AST.instantiate(:ast_sequence, nil)
210
+ nodes.each{|exp| seq_node.add_expression(exp)}
211
+ seq_node
212
+ end
213
+
214
+ def make_if(predicate, consequent, alternative)
215
+ if_node = Rubasteme::AST.instantiate(:ast_conditional, nil)
216
+ if_node.test = predicate
217
+ if_node.consequent = consequent
218
+ if_node.alternate = alternative if alternative
219
+ if_node
220
+ end
221
+
222
+ def make_formals(identifiers)
223
+ formals_node = Rubasteme::AST.instantiate(:ast_formals, nil)
224
+ identifiers.each { |identifier_node|
225
+ check_type(:ast_identifier, identifier_node)
226
+ formals_node.add_identifier(identifier_node)
227
+ }
228
+ formals_node
229
+ end
230
+
231
+ def make_combination(operator, operands)
232
+ proc_call_node = Rubasteme::AST.instantiate(:ast_procedure_call, nil)
233
+ proc_call_node.operator = operator
234
+ operands.each { |node|
235
+ proc_call_node.add_operand(node)
236
+ }
237
+ proc_call_node
238
+ end
239
+
240
+ def make_let(bindings, body)
241
+ check_type(:ast_bindings, bindings)
242
+ check_type(:ast_body, body)
243
+ let_node = Rubasteme::AST.instantiate(:ast_let, nil)
244
+ let_node.bindings = bindings
245
+ let_node.body = body
246
+ let_node
247
+ end
248
+
249
+ def make_bind_spec(identifier, expression)
250
+ spec_node = Rubasteme::AST.instantiate(:ast_bind_spec, nil)
251
+ spec_node.identifier = identifier
252
+ spec_node.expression = expression
253
+ spec_node
254
+ end
255
+
256
+ def make_bindings(bind_spec_nodes)
257
+ bindings_node = Rubasteme::AST.instantiate(:ast_bindings, nil)
258
+ bind_spec_nodes.each { |spec|
259
+ check_type(:ast_bind_spec, spec)
260
+ bindings_node.add_bind_spec(spec)
261
+ }
262
+ bindings_node
263
+ end
264
+
265
+ private
266
+
267
+ def check_list_type(obj)
268
+ obj.kind_of?(ListNode) || obj.kind_of?(Array)
269
+ end
270
+
271
+ def check_type(ast_type, ast_node)
272
+ if ast_node.type != ast_type
273
+ raise Error,
274
+ "wrong type node: expected=%s, got=%s" % [ast_type, ast_node.to_a.to_s]
275
+ end
276
+ end
277
+
278
+ def check_types(types, ast_node)
279
+ unless types.include?(ast_node.type)
280
+ raise Error,
281
+ "wrong type node: expected=%s, got=%s" % [ast_type, ast_node.to_a.to_s]
282
+ end
283
+ end
284
+
285
+ def expand_clauses(clauses)
286
+ # clauses must be an Array which holds CondClauseNode.
287
+ if clauses.empty?
288
+ SCM_FALSE
289
+ else
290
+ first = first_node(clauses)
291
+ rest = rest_nodes(clauses)
292
+ if cond_else_clause?(first)
293
+ if rest.empty?
294
+ sequence_to_node(first.sequence)
295
+ else
296
+ raise Error,
297
+ "ELSE clause isn't last: got=%s" % clauses.to_s
298
+ end
299
+ else
300
+ make_if(first.test,
301
+ sequence_to_node(first.sequence),
302
+ expand_clauses(rest))
303
+ end
304
+ end
305
+ end
306
+
307
+ def cond_else_clause?(clause_node)
308
+ clause_node.type == :ast_else_clause
309
+ end
310
+
311
+ end # end of Misc
312
+ end # end of AST
313
+ end