rbsiev 0.1.0

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